How to use auth with CognitoUserSession and ApiClientFactory? - android

I'm trying to authenticate against an Amazon Cognito Api, however it's not working...
Creating a CognitoUserPool for registering and signing in works. But how to proceed form here on?
In onSuccess(cognitoUserSession: CognitoUserSession) gives me a session, from which I can get a jwtToken (userSession.accessToken.jwtToken).
How to use the session in combination with the ApiFactor?
val api: DevetrackcommercialplaygroundClient = ApiClientFactory()
.apiKey(apiKey)
.build(Client::class.java)
val get= api.getFoo("id") // no auth; works
val post = api.postBar("id", something) // has auth; doesn't work
Always gives me 401. Both, if I set apiKey to the api key and also if I set it to the jwtToken.
So how can I use CognitoUserSession and ApiClientFactory in conjunction?

Seems like ApiGateway is not really meant to be used with user pools as the whole requests would needs to be created manually without any help from the sdk - same goes for the response.
See https://github.com/aws-amplify/aws-sdk-android/issues/767
Maybe this will change at some point in the future:
I agree with you that the Auth integration with API Gateway is not developer friendly and easy to use. We will take this feedback to the team to investigate on how to improve this integration. - kvasukib

Related

Android Sign in with apple and firebase flutter

I'm using sign_in_with_apple and I've got the signin working for ios but the android component is not working.
I've had a look through the docs and issues where this is asked but there are no clear answers. https://github.com/aboutyou/dart_packages/tree/master/packages/sign_in_with_apple
I'm stuck on the part of the docs for this plugin that say:
On the Sign in with Apple callback on your sever (specified in
WebAuthenticationOptions.redirectUri), redirect safely back to your
Android app using the following URL:
intent://callback?${PARAMETERS_FROM_CALLBACK_
BODY}#Intent;package=YOUR.PACKAGE.IDENTIFIER;scheme=signinwithapple;end
The PARAMETERS FROM CALLBACK BODY should be filled with the urlencoded
body you receive on the endpoint from Apple's server, and the package
parameter should be changed to match your app's package identifier (as
published on the Google Play Store). Leave the callback path and
signinwithapple scheme untouched.
Furthermore, when handling the incoming credentials on the client,
make sure to only overwrite the current (guest) session of the user
once your own server have validated the incoming code parameter, such
that your app is not susceptible to malicious incoming links (e.g.
logging out the current user).
The part that says: The PARAMETERS FROM CALLBACK BODY should be filled with the urlencoded body you receive on the endpoint from Apple's server. I'm unsure about how to get this and correctly format the PARAMATERS_FROM_CALLBACK_BODY part of the redirectURL to get this working for Android.
I was having exactly the same question and I actually opened up an issue on their repo yesterday.
I'm not sure if you are trying to set up your own backend server for callback or not, but to answer your question, the part you were having issue to understand is only apply for someone who need to implement their own API for call back.
I did get the Apple Sign In for Android to work(via web browser auth) with the following steps:
Note: Since you already got iOS part working, so I assume you got the basic configure taken care of already.
Set up the glitch.com service based off their document, this part is easy to follow.
And then you want to implement your signInWithApple call as the following reference Note: SERVER_AS_PER_THE_DOCS need update according to your glich service.
Future<FirebaseUser> signInWithApple() async {
var redirectURL = "https://SERVER_AS_PER_THE_DOCS.glitch.me/callbacks/sign_in_with_apple";
var clientID = "AS_PER_THE_DOCS";
final appleIdCredential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
webAuthenticationOptions: WebAuthenticationOptions(
clientId: clientID,
redirectUri: Uri.parse(
redirectURL)));
final oAuthProvider = OAuthProvider(providerId: 'apple.com');
final credential = oAuthProvider.getCredential(
idToken: appleIdCredential.identityToken,
accessToken: appleIdCredential.authorizationCode,
);
final authResult =
await SignInUtil.firebaseAuth.signInWithCredential(credential);
return authResult.user; }

How do I authenticate with Google's REST services using a GoogleSignInAccount?

I'm writing an Android application that needs access to Google's Calendar API. I'd like to avoid using the Google API Client Library in favor of a simple Retrofit REST implementation. However, I can't seem to get the right authorization credentials in order to complete Calendar API REST calls. In my app, I sign in successfully with the following options:
GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(Scope("https://www.googleapis.com/auth/calendar"))
.requestEmail()
.requestIdToken("WEB CLIENT ID HERE")
.build()
And I end up with a GoogleSignInAccount that gives me access to an idToken property. I've tried using this idToken as an OAuth 2.0 Bearer token in the authorization header of my request to the Calendar API, but I get rejected with a 401 every time. There's a lot of documentation around Google's OAuth process that seems to contradict itself or has escaped being updated, but it makes things very confusing. Any ideas about what I need to do in order to be able to use the REST APIs from my Android application?
Thanks, for the answer, I in-between managed to find out how to use the GoogleSignInAccount to authenticate the API-requests.
After you successfully signed in to your account using the google_sign_in plugin
(see the example for help) you can get the authentication headers that are required for the authentication of your api-request directly from the GoogleSignInAccount.
See:
GoogleSignInAccount _currentUser;
Future<Map<String, dynamic>> _getLabels() await {
http.Response _response = await http.get(
'https://www.googleapis.com/gmail/v1/users/'+_currentUser.id+'/labels',
headers: await currentUser.authHeaders,
);
return jsonDecode(_response);
}
authHeaders is implemented in Dart only, the source can be checked at https://pub.dev/documentation/google_sign_in/latest/google_sign_in/GoogleSignInAccount-class.html .
So the authHeaders are as follows:
"Authorization": "Bearer $accessToken",
"X-Goog-AuthUser": "0",
Now how can I obtain accessToken? Dart is calling GoogleSignInPlatform.instance.getTokens(email, shouldRecoverAuth: true); the impl of that method can be found here: https://github.com/flutter/plugins/blob/master/packages/google_sign_in/google_sign_in_platform_interface/lib/src/method_channel_google_sign_in.dart#L50
Aaaaand I'm giving up on this Google crap:
There is this magical chapter Obtain an access token from the Google Authorization Server. which says absolutely nothing on how to obtain access token. A prime example of shitty chatty useless doc that Google produces en masse.
The docu further sends me to https://developers.google.com/identity/sign-in/android/ which still doesn't explain how to get the accessToken.
That doc portal sends me to https://developers.google.com/identity/sign-in/android/start?authuser=2 which again talks web client instead of Android client, and I'm powerless. My limbs stop to move, my brain melts, my mouth opened in an endless silent scream of horror. This is how hell must look like. Reading Google docs is how hell must look like.

Android, Cognito: can sign in, but can't make authenticated AWS calls

In an Android app, I can successfully authenticate with Cognito, which returns a CognitoIdToken and a CognitoAccessToken.
But I can't figure out how to use that to make actual authenticated call to, say Lambda or S3. It seems that there's a chasm between CognitoIdentityProvider (which I seem to be able to work with) and CognitoCredentialsProvider (which I do not).
Thanks for ideas, or even a pointer to a sample that uses Cognito and authenticated calls / roles.
[edit] Bonus question: Can someone explain why there is an AWSCognito* and an AmazonCognito*, and why they seem almost completely unrelated?
Take a look at your Federated identities pool in the aws console. Look in the identity browser for the identityId that you are getting authenticated with (from your logs).
Here is the key thing: if the identity id does not show logins, then you never have gotten authenticated. *When I say logins, there is a login count on each identity, and it shows the identityProviderName that the authentication occured with if you click on the identityID.
This is a simple test, if you have logins you are authenticated. if you don't, you aren't. Now why none of the documentation at AWS says that... well.. who knows.
if you ARE authenticated, then the SDK stores the tokens, and you don't need to worry about it you can begin working with aws with your service configuration.
(The response is based upon the IOS sdk, but I believe for these matters, they are the same - The diagrams in here may help you, but these are my notes for IOS SDK, and I admit I have not tried this in Android).
I finally determined that I was missing calls to set the tokens into the credentials provider:
final CognitoCachingCredentialsProvider credentialsProvider = getCredentialsProvider(applicationContext);
Map<String, String> logins = new HashMap<String, String>();
logins.put(Constants.COGNITO_USER_POOL_LOGIN_STRING, cognitoUserSession.getIdToken().getJWTToken());
credentialsProvider.setLogins(logins);
where Constants.COGNITO_USER_POOL_LOGIN_STRING is like "cognito-idp.us-west-2.amazonaws.com/" + MY_COGNITO_USER_POOL_ID. After doing that, a TransferUtility object was able to download with authentication. The TransferUtility was previously obtained like this (edited):
CognitoCredentialsProvider cp = . . .
AmazonS3Client s3Client = new AmazonS3Client(cp);
TransferUtility s3transferUtility = new TransferUtility(s3Client);

How to implement server side sessions in node.js with express for an android app?

Hello all i am making an android app in whiich i have multiple account login at a time now my question is that i for multiple logins i should use sessions to verify every account user that is logged in. Now i am using express on the server side i have read a lot of documentation on storing sessions in node.js
Express-session (Though it is only good for development but not for production but not for my app)
Cookie-session
connect-Redis
connect-mongo
I have also heard about json web tokens where i can generate unique tokens and then i can pass the tokens to the client using res.json({user_id:"user1", token: "generated_token here"})
I have also heard about passport but dont know how it is going to do this also as in passport i use express-session by default will it be good for production or not ??
Now my first question is i have read all of there docs and nowhere it is mentioned where i am creating unique tokens for every user that is signing up.
Second question as i am using my server for android app there will be no use of cookie i will be sending user token as in parameter req.body.token now how to cmpare this with current user_id.
Actually i dont get the flow of control i mean how everything is going on in session in node.js. Also what is this secret is this thing generating unique tokens or what. Also i mean about 100000 of users are registered for my app now please tell me accordingly which way should i use for my app.
I have asked this question previously but there i did not mention that as i am not making a website how to do this(As in my case there will be no use of tokens)
I know this question i am asking is very vague but please bear with me i just want to understand how sessions are used in node.js
Thanks Anways
I'll try to answer this, but it is vague (as you pointed out). I'm going to make an assumption that your Android app is a native Android app and is going to be connecting to some sort of NodeJS backend in the cloud that is based on ExpressJS. If that's not the case, please clarify your thoughts in an update to your question.
The best idea for this specific scenario is to look to the cloud provide. Azure App Service Mobile Apps, for example, allows you to implement authentication - it eventually returns a JSON Web Token (http://jwt.io) to authenticate each request.
If you don't want to be beholden to a cloud provider, but want to run it yourself, you are going to have to implement the token generation and checking yourself. This generally follows the form:
Set up a WebAPI endpoint (maybe /signin) which takes whatever token the identity provider gives you, verifies the information and returns a JWT - there is an NPM module (jsonwebtoken) for producing the JWT. Ensure the JWT includes the identity of your user. I tend to use email address for the identity.
Your Android application will do a WebAPI request to your backend with an Authorization header, the value of which is "Bearer "
Your NodeJS API will use JWT authorization to validate the JWT and extract the user identity so you can use it in your API logic.
The important thing to note in this specific scenario is that your backend code is implementing a WebAPI - there are no cookies nor sessions in the API. The only thing that is linking the user from the client code to the backend code is the JWT.
As a short piece of code, here is how you verify a JWT:
var express = require('express');
var app = express();
var jwt = require('express-jwt');
var jwtCheck = jwt({
secret: new Buffer('your-jwt-secret', 'base64'),
audience: 'your-jwt-audience'
});
app.get('/api/protected', jwtCheck, (req, res) => {
// Your code here
});
app.listen(process.env.PORT || 3000);

Authenticate my "app" to Google Cloud Endpoints not a "user"

What I'm trying to do is to authenticate my Android app to the Google Cloud Endpoint.
Basically the endpoints should only allow my Android app to access the methods and nothing else.
I have done these things -
Create a client id using my SHA1 value in Eclipse in the Google Cloud Console.
Create a web client id in the Google Cloud Console for my endpoint project.
Add both these client id's in the "#Api" mentioned on each endpoint.
Add an extra "user" parameter in the endpoint methods.
Regenerate and deploy the backend to the cloud.
But when I'm running this the "user" is always coming as "null". I'm at my wits end trying to find a proper working method for doing all this.
I've searched many forums but no proper answers anywhere.
Here's another similar post Restrict access to google cloud endpoints to Android app
This is the reference I'm using -
https://developers.google.com/appengine/docs/java/endpoints/auth
Has anyone here done this before? My main goal is to not allow unauthenticated apps and outside world to access the endpoints, for obvious security reasons. I don't want to use end-user based authentication since I want to keep my app very simple.
It sounds like it's working as intended. You control which client apps can call your endpoint methods via the client IDs as you have already done. The User parameter is coming in as null precisely because you aren't doing end-user authentication. The User parameter represents an actual real user (Google Account). So if you don't need end-user authenticated methods, you can just simply not define the User parameter, or else ignore the null value. You said your problem is that the User parameter is set null. What are you expecting it to be in this scenario?
You need to call authenticate on the client, then possibly the library you're using will 'inject' the user information.
Here's what worked for me :
Let's say you have the keys below :
static final String WEB_CLIENT_ID = "somekeyfor webclientid.apps.googleusercontent.com";
static final String ANDROID_CLIENT_ID = "somekeyfor androidclientid.apps.googleusercontent.com";
static final String ANDROID_AUDIENCE = WEB_CLIENT_ID;
Your Api anotation should look like this :
#Api(
name = "yourapiname",
clientIds = {CloudEndpoint.WEB_CLIENT_ID,CloudEndpoint.ANDROID_CLIENT_ID},
audiences = {CloudEndpoint.ANDROID_AUDIENCE},
version = "v1",
namespace = #ApiNamespace(
ownerDomain = "myapp.app.com",
ownerName = "myapp.app.com",
packagePath = ""
)
)
In the annotation below, notice how your audience is the variable --> ANDROID_AUDIENCE which is equal to WEB_CLIENT_ID.
Now in your app side, when you create the googleAccountCredential object, you should pass in the Web Client Id like this :
mAccountCredentials = GoogleAccountCredential.usingAudience(getApplicationContext(),"server:client_id:" + "yourwebclientID");
Note that even if this is properly done, your user object in the endpoint might still coming out as Null if the account name you pass in mAccountCredentials.setSelectedAccountName("accontname") does not exist in the device. Therefore make sure the account name you pass does exist in the Android device by going to --> (Settings/Accounts)

Categories

Resources