I'm using implicit grant for one particular client (web-based admin portal) for an application that uses Cognito-integrated auth for other parts of the application (API Gateway, etc).
The problem is, the id token I get from Cognito Oauth expires after one hour, but I still need that token to send to API Gateway to signify that I have an authenticated user.
How do I get a new id token (remember, I'm using implicit grant, so I don't have a refresh token)?
Do I have to re-send the user's credentials to Cognito's auth endpoint every hour? That seems extravagantly un-secure for several reasons.
What am I missing?
Thanks in advance!
If you use implicit grant there is no way of refreshing the tokens (Storing credentials and using it to get new id tokens doesn't count here since its takes away the purpose of using OpenID Connect).
This is why the code grant is there. Unless you use code grant, refreshing the tokens are not possible.
You can use AWS Amplify library to simplify the login where it takes cares of the refreshing and other heavy liftings if you use the code grant including using federated identities to access AWS resources such as S3.
Related
I would like to use Amazon cognito as a way to allow users to sign up to my app and validate api calls, so I don't have to handle user passwords or create a custom account recovery email system.
The problem is im not sure I understand how its supposed to work or what tools I am meant to use. Heres how I imagine it:
This way I could use cognito to identify users and authorize api calls.
But I am not sure if this is correct. For example I'm not sure if the frontend is supposed to refresh the tokens or the backend.
I am also not sure if I am meant to implement the code for exchanging and refreshing the token and logging out of users myself, but it seems that way since I can't find any tools that would do that for me.
I have found some libraries concerning aws cognito, but none of them mention exchanging or refreshing tokens:
https://www.npmjs.com/package/amazon-cognito-identity-js
https://www.npmjs.com/package/amazon-cognito-auth-js
https://www.npmjs.com/package/#aws-cdk/aws-cognito
I did find this library mentioned in the documentation that can be used to validate jwt id tokens on the backend.
https://github.com/awslabs/aws-jwt-verify
I am using userpools and no identity pools, since I don't grant users access to my aws resources.
So basically my question is, is my perception of the cognito workflow correct and if yes, how can I exchange the grant code for an id token and how can i use the refresh token to refresh the id token.
I have an API Gateway/lambda REST API that is being accessed from a react web app. I need to add authentication using google as an identity provider. The app should also keep the user signed in.
I understand when the user first grants access to the (react) client app, it should send the ID token to my backend, which should then verify the token.
Since my architecture is serverless, I assume the verifying should be done in the API Gateway authorizer function, which then grants access to the API on successful verification of the token.
My question is, how do I then create a persistent session? Should I be saving anything to my database about the user? Does the token need to be verified on every API call?
Should the authorizer be checking if the user is already registered or if it's a new user?
It would be easiest to use AWS Cognito for this. Configure a user pool as an authorizer for your API gateway and then configure Google as an identity provider for that user pool. This link might be helpful: https://docs.aws.amazon.com/cognito/latest/developerguide/google.html. Cognito even has a hosted UI if you want to use it for signing users in.
As for your question about persisting user sessions, they usually get persisted in local storage in the browser or in a cookie or some similar mechanism. You can also persist them on the server-side in a database like you were mentioning but that isn't really for authentication purposes.
The user session will contain an access token. The access token is short-lived, meaning you can only use them for an hour usually. After that you have to use a separate refresh token to generate a new access token. And to be extra safe the refresh token itself will expires after a few days (and you have to sign back in).
I have got one beginners questions. I am just starting with AWS Cognito User Pools and set oAuth "Authorization Code Grant" workflow succesfully - so now, after the login, I am succesfully redirected and get the authorization code in the url. The next step is to exchange it for the actual JWT token, but the problem is that I miss some broader perspective and dont know whats the best practice in this case. I know the javascript code to exchange the code for token, but I dont know where it should run.
Shall I use Triggers functionality in my user pools, tie Lambda function to some event (which one? "Post Authentication"?) and let this Lambda function exchange the code for token and save it as a session?
Or shall I put all this functionality into the url I redirect to after a successful login? Is there some best practice for this situation?
Thank you
The question to ask is: "Now the user is authorized.. now what?"
The AWS services that you want to make available to your users will determine what type of authentication flow you need to use. Since your question is fairly broad.. I will give you the high level of two types of authentication flow.
Federated Identities:
You can configure federated identities to grant users AWS IAM credentials (AccessKey and AccessSecret). When you set up a Federated Identity Pool, you specify the identities that can receive IAM credentials (for example: Your cognito pool, google, any other openID provider) and the IAM policy which will grant access to specified resources. This guide will review how to do this in your application code.
API Gateway Custom Authorizer You can also configure a Custom Authorizer with the source being your Cognito User Pool. This will allow you to make a request using the jwt #id_token received from authenticating against the user pool.
Specific answers to questions:
Shall I use Triggers functionality in my user pools, tie Lambda function to some event (which one? "Post Authentication"?) and let this Lambda function exchange the code for token and save it as a session? - Generally Triggers are used to store user data for analytics or server side processing. If you are using Cognito for authentication you don't need to use Lambda
Or shall I put all this functionality into the url I redirect to after a successful login? Is there some best practice for this situation? - I would recommend using a library such as AWS Amplify to manage Authentication with Cognito.
Most common approach I have seen with recommendation for code grant flow is the approach you mentioned,
shall I put all this functionality into the urlĀ I redirect to after a
successful login
The advantage of this is that you can store the refresh token server side and use it to refresh the id_token before it expires (There are several places which states not to store the refresh token client side).
However, if you look at the implementation in AWS AmplifyJS library for Code Grant, it does this in client side storing the refresh token also in local storage and refreshes the id_token from client side using JavaScript.
So both approaches are there while using both in different projects, I feel the latter is easy to implement and maintain.
I am trying to add a Google login through Amazon Cognito, I have setup everything needed, I have also configured the attribute mapping from google to my pool attributes, I've mapped 'access_token' attribute to 'google_access_token' attribute and 'refresh_token' to 'google_refresh_token'. When sign in process starts, google prompts me for required permissions needed and redirects back to my app, and I can see on cognito dashboard that user is added with access token mapped in 'google_access_token' but no refresh token there. I double checked every configuration everything seems fine. I also tried mapping other attributes like 'token_type' and 'expires_in' those are getting mapped except the refresh token.
I found out that for generating refresh token from google, client need to pass 'access_type=offline' parameter in the GET parameters which Amazon Cognito DOESNOT send while starting OAUTH login with google, so google doesnt provide google refresh token. So in nutshell there is no way ( Atleast now ) to get refresh token from google and access google APIs "offline" if you are using Amazon cognito. Alternatively I used Auth0 which supports this and can send access_type parameter to google and can store refresh token.
If I may ask, have you seen this document?
Understanding Amazon Cognito user ool oauth 2.0 grants
To get to the point, this concern may be because of the OAuth Flow we have set in the Cognito User Pool. We need to use "Authorization Code Grant" as the OAuth flow. Implicit Grant doesn't generate refresh tokens, but Authorization Code Grant does.
If you're using Amplify framework in your project, this framework will do most of the heavy lifting for you. You just need to setup the User Pool's app client correctly and configure Amplify for that specific app client.
I hope this helps.
When I signed in using google from aws cognito login page, it return back aws access token. Is it possible to retrieve google access token and refresh token using aws token.
The url used to login -
https://example.auth.ap-southeast-1.amazoncognito.com//login?redirect_uri=redirect_uri&response_type=token&client_id=client_id.
How aws cognito handles refresh token when signed using google?
In short, no.
When you use the above URL to sign in using Cognito Userpool's OAuth endpoints, the response from google (i.e. tokens) is sent to the OAuth response endpoint for your userpool's domain ( https://example.auth.ap-southeast-1.amazoncognito.com/oauth2/idpresponse ). Cognito checks the response from Google and generates id, access & refresh tokens and returns these to you depending on the scope and auth flows used. The response from Google i.e the google tokens is not stored somewhere and there are no Cognito API calls to retrieve the same.
As for token refresh when signed in using Google, that depends on your refresh token (returned by Cognito, and not Google's refresh token). As long as the refresh token returned from Cognito is valid, you can use it to get new id/access tokens. Again, this process does not involve Google at all.
Not a fully working solution, but you can create custom attributes in cognito, and map them in the attribute mapping screen :
Then when the user logged in, I saw that access_token and expired_in are captured. But I do not see refresh_token. Without refresh_token we wont be able to access the api from the backend. This seems so close alas !
I'm gonna build off of Sourav Sarkar's answer with an idea that you can try. If you setup Google as an OIDC provider (not the one built in Cognito) you may be able to try adding either one of these scopes:
offline
offline_access
The reason why we have to include these is because by default, Google only returns the Access Token and not the Refresh Token. You have to specify that you would need the refresh token to retrieve it.
Fair warning though, I am not sure which one will work nor if adding any scope will work either since I have not tried it myself.
If you really need the refresh token for some reason e.g. Google API calls, you can use Auth0 as this is built into their product. I have not tried that either and this is also a problem I am facing right now since I don't want to use Auth0.
Here are my references:
AWS OpenID Connect Oath 2.0 Scopes Google OAuth 2.0