I am integrating AWS cognito authentication with social login (facebook/google).
I am follow all the steps as given in documentation but the end return Invalid Access Token
Service: AmazonCognitoIdentityProvider;
Status Code: 400;
Error Code: NotAuthorizedException;
Request ID: 58fc3cfc-1649-11e9-91bc-3fb47a1bd404
Put facebook login in to the crendential provider this code generate identity in my identity pool :
Map<String, String> logins = new HashMap<String, String>();
logins.put("graph.facebook.com",
AccessToken.getCurrentAccessToken().getToken());
credentialsProvider.setLogins(logins);
for creating user in user pool i am using this url:
val url = "https://<my-domain-name>.auth.ca-central-1.amazoncognito.com/oauth2/authorize?redirect_uri=myapp://&response_type=token&client_id=<my-ClientId>&identity_provider=Facebook"
That url creating my user in user pool and return access token and id token in result below :
access_token=eyJraWQiOiJyUXpaTDRUVGt6UDdoU3ZDbVB0NktpTVZDcXB4Z2ZFT3pJckpCWFB0WXZVPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI2OTIwZDUwZC0zMTU4LTQwMTYtOTgyMi0wNDc0Yzc1MDFjYjIiLCJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6ImF3cy5jb2duaXRvLnNpZ25pbi51c2VyLmFkbWluIHBob25lIG9wZW5pZCBwcm9maWxlIGVtYWlsIiwiYXV0aF90aW1lIjoxNTQ3Mjg4NDc0LCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuY2EtY2VudHJhbC0xLmFtYXpvbmF3cy5jb21cL2NhLWNlbnRyYWwtMV9DSFVMbDV5c2wiLCJleHAiOjE1NDcyOTIwNzQsImlhdCI6MTU0NzI4ODQ3NCwidmVyc2lvbiI6MiwianRpIjoiNDE4MjNmNzUtMGFkMC00MTdjLThhOTYtM2JjZDM0NWNlZDQ3IiwiY2xpZW50X2lkIjoiN244Z25tdXFuM3NzZWFnaGNoOGQ2OWRibTIiLCJ1c2VybmFtZSI6IkZhY2Vib29rXzE5NDkyNzI0OTg1MDM3ODcifQ.GhaV996dFl7vx-tdkhhuq5HeSG0K5Tn20arF4M2i6YyRdm12mGJBWfmStOLLTzvYzz9ABRcIRmvy8imTSblafKMEqfDoRXn475g3xt0qs-omQTF2aFO_fi1wCCAMqT2Tb7LNG0CnGrcVXyutf3xB6vRg7ge7u6WPOEZqkLqf5bq2e5MMYCFSdqPIVMwnfV0AH6lGROCPr8GqHz8vPM3tdvSGMQYVL7PcL9I3IXgA354qt91RcqrXV_kxSkOFpysyJHB_eii0Wgrxe_zNFZvfx41ox7WlrVArZF9wF5VoqDF55160EJjlFwTqehmplZLh10rBhGn9ygpYLMSByibyKA
&id_token=eyJraWQiOiJ6ellnUlNYNDlMNzNEaWNLdEE4dWowOTF3akpNWHI1M2JnMjJJbW93QnF3PSIsImFsZyI6IlJTMjU2In0.eyJhdF9oYXNoIjoiekQ3WkZSVTFia2FOcXJQSWltV2h2dyIsInN1YiI6IjY5MjBkNTBkLTMxNTgtNDAxNi05ODIyLTA0NzRjNzUwMWNiMiIsImF1ZCI6IjduOGdubXVxbjNzc2VhZ2hjaDhkNjlkYm0yIiwiaWRlbnRpdGllcyI6W3sidXNlcklkIjoiMTk0OTI3MjQ5ODUwMzc4NyIsInByb3ZpZGVyTmFtZSI6IkZhY2Vib29rIiwicHJvdmlkZXJUeXBlIjoiRmFjZWJvb2siLCJpc3N1ZXIiOm51bGwsInByaW1hcnkiOiJ0cnVlIiwiZGF0ZUNyZWF0ZWQiOiIxNTQ3MjExMjg1MTEzIn1dLCJ0b2tlbl91c2UiOiJpZCIsImF1dGhfdGltZSI6MTU0NzI4ODQ3NCwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmNhLWNlbnRyYWwtMS5hbWF6b25hd3MuY29tXC9jYS1jZW50cmFsLTFfQ0hVTGw1eXNsIiwibmFtZSI6IkpheSBWZXJtYSIsImNvZ25pdG86dXNlcm5hbWUiOiJGYWNlYm9va18xOTQ5MjcyNDk4NTAzNzg3IiwiZXhwIjoxNTQ3MjkyMDc0LCJpYXQiOjE1NDcyODg0NzQsImVtYWlsIjoianYudmVybWEyOUBnbWFpbC5jb20ifQ.dK5D1Z1IIeEGdmDI6mbTV48580Rr26_ekQ7za6GrtGADQpm06Fgvtj2SJhv35u6kI6KVnCbNoRC9ewoGB8QmWFCvL2VI-djdDqbCrHSTKsb9RkG1PsfFXoFezvlv4NROc7p5pFPTrltZVH1oI2nf6bAtcMEp7Cp0v_NaYt8dJ0cdYslIGwikH3Dm1QiNKzoqkkUy1-fjwLRSJ5CiH9eUO8DvzB6VomNOHHN0A5F-EJbIAZFXiD3z9N86TsRyEKSpaR7JhmO20VVVLp_YvpUuY9Nagiknkx3gp08vYCBBro0dTnDDQSsOqfVTlNTI5QZz_7AQXrUl7iyAMcw91mfajw
&token_type=Bearer
&expires_in=3600
In last step I am make get user request and send accessToken as a parameter.
After hitting this API, I have got Invalid Access Token
Service: AmazonCognitoIdentityProvider;
Status Code: 400;
Error Code: NotAuthorizedException;
Request ID: 58fc3cfc-1649-11e9-91bc-3fb47a1bd404)
Invalid Access Token (Service: AmazonCognitoIdentityProvider;
Status Code: 400;
Error Code: NotAuthorizedException;
Request ID: 58fc3cfc-1649-11e9-91bc-3fb47a1bd404)
Can you try deleting your app from facebook settings and try login again.
Finally got the solution just adding endpoint manually according to my region in my request.Now Facebook and google login working fine with 'AWS Cognito'.
Related
I am using CognitoAuth library from Amazon to manage user authentication.
In the AWS console, the "Do you want to remember your user's devices?" option is set to 'Always'.
But when I call getSession method on a CognitoUse object, in onSuccess callback, I always do get 'newDevice' param as null. It is supposed to be not null because the option to remember device is enabled. Because of that I cannot refresh the token and getting the exception below:
Device confirmation failed:
com.amazonaws.mobileconnectors.cognitoidentityprovider.exceptions.CognitoNotAuthorizedException: User is not authenticated
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.getCachedSession(CognitoUser.java:981)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.confirmDevice(CognitoUser.java:3287)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.handleChallenge(CognitoUser.java:2607)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.respondToChallenge(CognitoUser.java:2409)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser$24.run(CognitoUser.java:2480)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.continuations.AuthenticationContinuation.continueTask(AuthenticationContinuation.java:124)
at com.amazonaws.mobile.client.AWSMobileClient$6$1.getAuthenticationDetails(AWSMobileClient.java:1177)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.getSession(CognitoUser.java:778)
at com.amazonaws.mobile.client.AWSMobileClient$6.run(AWSMobileClient.java:1137)
at com.amazonaws.mobile.client.internal.InternalCallback$1.run(InternalCallback.java:101)
at java.lang.Thread.run(Thread.java:764)
Caused by: com.amazonaws.services.cognitoidentityprovider.model.NotAuthorizedException: Invalid Refresh Token. (Service: AmazonCognitoIdentityProvider; Status Code: 400; Error Code: NotAuthorizedException; Request ID: ed2f2501-7a36-447f-ac29-c4ab4741958e)
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:730)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:405)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:212)
at com.amazonaws.services.cognitoidentityprovider.AmazonCognitoIdentityProviderClient.invoke(AmazonCognitoIdentityProviderClient.java:6292)
at com.amazonaws.services.cognitoidentityprovider.AmazonCognitoIdentityProviderClient.initiateAuth(AmazonCognitoIdentityProviderClient.java:4277)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.refreshSession(CognitoUser.java:2378)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.getCachedSession(CognitoUser.java:976)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.confirmDevice(CognitoUser.java:3287)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.handleChallenge(CognitoUser.java:2607)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.respondToChallenge(CognitoUser.java:2409)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser$24.run(CognitoUser.java:2480)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.continuations.AuthenticationContinuation.continueTask(AuthenticationContinuation.java:124)
at com.amazonaws.mobile.client.AWSMobileClient$6$1.getAuthenticationDetails(AWSMobileClient.java:1177)
at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.getSession(CognitoUser.java:778)
at com.amazonaws.mobile.client.AWSMobileClient$6.run(AWSMobileClient.java:1137)
at com.amazonaws.mobile.client.internal.InternalCallback$1.run(InternalCallback.java:101)
at java.lang.Thread.run(Thread.java:764)
Why is no CognitoDevice object received? How to resolve this?
I'm developing an Android app and keep having issues accessing S3 bucket "through" Cognito.
I'm managing to connect to my cognito pool, with a username and a password of a specific user from my pool:
AWSMobileClient auth = AWSMobileClient.getInstance();
auth.signIn("username", "password", new HashMap<String, String>());
if (auth.isSignedIn()) {
ActivityUtils.startActivity(this, MyActivity.class);
}
My user in the pool is assigned to a group with attach S3 role:
Role ARN arn:aws:iam::<my account number>:role/Cognito_S3_Full_Access
Which contains those permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
]
}
When I'm trying to use the "AmazonS3Client" I created using the credentials from the "AWSMobileClient" I keep getting errors. I create it in this way:
AWSMobileClient awsMobileClient =AWSMobileClient.getInstance();
AmazonS3Client s3Client = new AmazonS3Client(awsMobileClient);
And the error that I got is:
2019-05-20 17:56:21.645 27019-27019/com.mycomp.mypackage E/S3Uploader: Error upload file to S3 bucket : Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: 375C07384A904483)
When I'm creating the "AmazonS3Client" using HARD-CODED accessKey and secretKey of a new "IAM" user that I created and attach the same policy as above it working as expected.
I'm using it this way:
BasicAWSCredentials credentials = new BasicAWSCredentials("myAccessKey_hsjgfhjsdg", "mySecretKey_asdhasjkdha");
AmazonS3Client s3Client = new AmazonS3Client(credentials);
But I don't want to fill up my app with hard coded password, especially that I already manage to connect using the user input of his username and password
Some notes: when I trying to get the secret key and access key after login with Cognito I can see that I get different token every login, so I guess this part is working.
So my question is what am I doing wrong?
How can I make the "AmazonS3Client" to use the session and role permission of the log-in user and his assigned group?
I had everything set up properly and was getting the same Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID: 8D650E2CCCD58E34)
What I missed was the condition in the S3 template:
"Condition": {
"StringLike": {
"s3:prefix": [
"public/",
"public/*",
"protected/",
"protected/*",
"private/${cognito-identity.amazonaws.com:sub}/",
"private/${cognito-identity.amazonaws.com:sub}/*"
]
}
}
Basically your keys have to start with these prefixes, depending on the policy. I didn't think much of the public/s3Key.txt example key in the Amplify docs.
private val transferUtility = TransferUtility.builder()
.context(context)
.s3Client(AmazonS3Client(AWSMobileClient.getInstance(), Region.getRegion(Regions.EU_WEST_1)))
.awsConfiguration(AWSMobileClient.getInstance().configuration) // use the generated s3 template
.build()
transferUtility.upload("public/$key/${file.name}", file)
I am trying to generate server auth code in android
gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestScopes(new Scope(Scopes.DRIVE_APPFOLDER))
.requestServerAuthCode(getString(R.string.server_client_id), false)
.build();
Then I have tried to get server auth code like this.
result.requestServerAuthCode(getString(R.string.server_client_id), false)
Suppose i got a auth token like 'bla bla bla';
Then using laravel socialite I am trying to get user on the server side
Socialize::driver('google')->userFromToken('bla bla bla')
It shows me error
GuzzleHttp\Exception\ClientException with message 'Client error: GET https://www.googleapis.com/plus/v1/people/me?prettyPrint=false resulted in a 401 Unauthorized` response:
{"error":{"errors":[{"domain":"global","reason":"authError","message":"Invalid Credentials","locationType":"header","loc (truncated...)
Actually the code sent by google on android is not the access token to get access token you can do this on laravel controller.
Install this composer library https://github.com/pulkitjalan/google-apiclient
$client = new \PulkitJalan\Google\Client(['client_id' => 'YOUR_CLIENT_ID', 'client_secret' => 'YOUR_SECRET', 'redirect_uri' => 'YOUR_REDIRECT_URI', 'developer_key' => 'YOUR_KEY']);
$google = $client->getClient();
$google->authenticate($token);
$access_token = $client->getAccessToken()["access_token"];
//and now here you go
$user = Socialize::driver('google')->userFromToken($access_token);
The easiest way is to use the Google_Client class that is provided from Google. you can find it here
Now, you've got two option:
You can send an id_token to the server, and validate it just as the link said and then just fetch the user info from the object received.
You can send the backend_auth_code to the server instead of the id_token, and then use the method fetchAccessTokenWithAuthCode($code) of the Google_Client class. This gives you the access token, id token and other stuff. You can then use that access_token with Laravel Socialite
$client = new Google_Client([
'client_id' => config('services.google.client_id'),
'client_secret' => config('services.google.client_secret')
]);
$data = $client->fetchAccessTokenWithAuthCode($code);
$user = Socialite::driver('google')->scopes(['profile','email'])->userFromToken($data['access_token']);
I have a login/logout module in my django app (using DRF).
it works in token authentication - when user logs in he passes a username and a password and gets a token, that can be used forever.
(I save the token in my client app).
when he logs out - I delete the token from the client app.
The problem I noticed is that when one client (android app) in logged in with user1 for example (currently has the token that was achieved from the server), other clients can login as the same user (provide same username and password and get the token) - and now I have both clients logged in as user1.
Here is the django code for getting the token:
class ObtainAuthTokenAndUser(APIView):
throttle_classes = ()
permission_classes = ()
parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
renderer_classes = (renderers.JSONRenderer,)
serializer_class = AuthTokenSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
user_serializer = UserSerializer(user)
return Response({'token': token.key, 'user': user_serializer.data})
obtain_auth_token_and_user = ObtainAuthTokenAndUser.as_view()
What can I do in order to prevent this situation??
In the case of another client tries to log in with a already logged in user - I want to send a "already logged in from another device" message and a 401 HTTP.
Any ideas about how to approach this?
You can simply check if any valid token is already present in the database for the same user.
token, created = Token.objects.get_or_create(user=user)
instead of above method you should use
try:
token = Token.objects.get(user=user) // Chcck if token is present
except Token.DoesNotExist:
token = Token.objects.create(user=user) // Create new token, no token for this user
else:
return Response({'error': 'Already logged in', status=400})
I am using https://github.com/Wizcorp/phonegap-facebook-plugin to connect my cordova Android app to Facebook.
I can login with:
facebookConnectPlugin.login(["email"],
fbLoginSuccess,
function (error) { alert("ERROR:" + JSON.stringify(error)); }
);
, logout even call facebookConnectPlugin.getLoginStatus and get:
userID
accessToken
expiresIn
sig
status
but when FB.api('/me', function(response){...}) is called, I receive
{error:
{
message: An active access token must be used to query information about the current user,
type: OAuthException,
code: 2500
}
}
Also this only happens when the app is built, not tested in browser.
Solved issue by manually giving FB.apicall a token with:
FB.api('/me?access_token='+userdata.authResponse.accessToken, function(response) {...
where userdata is the response of facebookConnectPlugin.getLoginStatus
I just don't understand why doesn't it provide token automatically in android app like it does in browser.
Send the access token and the data retrieving fields with the apiString
const fields = ['email', 'first_name', 'last_name', 'gender', 'birthday', 'picture.type(large)'];
const apiString = `me?access_token=${accessToken}&fields=${fields.join(',')}`;