amazon-cognito-auth-js
amazon-cognito-auth-js copied to clipboard
Refresh access and id tokens in a React/Angular SPA
Summary
I would say that without Cognito implementing prompt=none on the /oauth2/authorize endpoint, and whilst the cognito cookie on <your_domain>.auth.<region>.amazoncognito.com/ expires after 60 minutes instead of 30 days (or what is set for the user pool) it is unsuitable to be used as an out-of-the-box solution for Single Page Applications.
Details
The recommended OAuth2 flow for a Single Page Application (SPA) is the Implicit Grant. This flow, by design, does not issue a refresh token to the web app.
There are many issues in this project around refreshing tokens that seem to be resolved by switching to Authorization Code Grant instead, which is OK for some native apps and some non-SPA web apps (e.g. where there are round trips to a server) but is unsuitable for SPA apps.
It is considered unsafe and bad practice for a web application to store a refresh token in session storage, local storage, or in javascript accessible memory as this opens up the app to many attacks which could result in the refresh token being exposed to a malicious third party which is now able to obtain ID/API tokens for the user.
The OpenID Provider (OP) usually sets an http only secure cookie on user login, and this is used for refreshing in this case the OP is awscognito and the cookie would be set on <your_domain>.auth.<region>.amazoncognito.com/. Cognito does set this cookie.
The typical process for refreshing tokens in an SPA is to call the OP's authorize endpoint with a prompt=none in the query string. This would normally occur in an embedded iframe in the SPA so as to not alter the UI and would either return new tokens which can be stored or an error, which deletes the tokens.
This is not a standard or requirement as it is up the the OpenID Provider to determine how a user is authorized, however if this is not implemented and it means that an SPA must choose to log in whenever the access token expires, or to adopt poor practices and store refresh tokens in the SPA (there is another option where we could have our own server which stores the refresh tokens and can refresh api/id tokens and deliver them to the SPA).
This partially works using cognito hosted UI, there is a cognito cookie stored when you login at <your_domain>auth.<region>.amazoncognito.com/login?client_id=<your_client_id>&response_type=token&redirect_uri=<your_redirect> and if you subsequently call <your_domain>auth.<region>.amazoncognito.com/oauth2/authorize?client_id=<your_client_id>&response_type=token&redirect_uri=<your_redirect> it will redirect with new tokens, with updated timestamps, without requiring interaction.
Unfortunately the cognito token expires after 60 minutes so it can only be used to extend the session to a maximum of 120 minutes. Also since the prompt parameter is not implemented there is no way for the iframe to get an error so it cannot be used in an iframe.
References
- prompt=none behaviour, OpenId spec section 3.1.2.1. Authentication Request
- AWS specs for authorization endpoint This does not detail prompt as an option and it appears to not be implemented.
- Auth0 silent authentication for SPAs
- Okta silent authentication for SPAs
Any thoughts on this? It seems to me that it makes implicit grant totally impractical to use.
I'd prefer if AWS allows the configuration the id_token and session cookie expiry TTL based on your own requirements.
This seems like a deal breaker for using Cognito User Pools for SPA development. I am seeing the cognito cookie valid for 8 hours though now, so that is a little better. I agree though that without the prompt=none option, the re-authorize cannot be transparent to the user.
Why there is no response from aws team on this??? This is making implicit flow absolutely useless. I am not sure how @cervantek got cognito cookie to work for 8 hours. I see only 1 hour, so you are stuck with maximum 2 hour for tokens if you do a workaround and make a call to oauth2/authorize endpoint for hosted login.
Wondering the same thing! This is a MUST feature for any real-world use.
This seems to be a vital feature for user experience. @cervantek do you have details on how to increase the cognito cookie timeout? Though even that would not fully solve the issue.
The document that you referenced assumes that refresh tokens last indefinitely, but I believe that with Cognito User Pools you can configure the refresh token TTL
I don't know what security experts think about e.g. reducing the refresh token TTL to 1 day and storing it in the local storage of a SPA, but it seems no worse than increasing the TTL of the access token.
AWS needs to implement this properly by giving us the ability to configure cognito cookie timeout. If implemented, then using a proper Oidc JS library would get a new id_token and token periodically.
We need this feature too
I agree with @nihakue . After talking to AWS team we went with that solution - setting refresh token ttl to 1 day, and doing refresh token every hour with auth code flow.
@ppasmanik @nihakue Although this is technically possible, it’s considered bad practice to store refresh tokens for SPA apps. AWS really needs to close in on this so they don’t keep putting applications at risk.
Could someone from the AWS team respond to this? Came across this issue whilst trying to implement silent refresh. I am now considering moving away from Cognito to something that supports the implicit flow better for SPAs.
Could someone from the AWS team respond to this? Came across this issue whilst trying to implement silent refresh. I am now considering moving away from Cognito to something that supports the implicit flow better for SPAs.
@rajwilkhu It's been very quiet for a long time. Choose something that supports silent refresh.
While this may sound (very) crazy. What if the refreshToken had a more granular TTL, such as minutes or hours. Wouldn't this get us slightly closer to a silent auth/refresh solution?
@maziarz while it might help, it's actually the wrong solution. Refresh tokens shouldn't be used in SPA apps; rather, use the session cookie controlling the refresh, e.g. cognito to use session cookie to see if session cookie is still valid and reissue another token and update session cookie if warranted.
@salmonz its not that i disagree, i ran into this problem 1.5 years ago and ended up implementing Cognito with passport.js in the back utilising secure cookies. But eventually it removed all benefits from being truly "serverless" and having low maintenance on a SPA. I do not believe that anyone has solved this issue in an elegant way, even auth0 is relying on a valid SSO session in order for this to actually work with prompt=none. It does not look like Cognito team are going to introduce a cookie mechanism any time soon..
AWS - do you have an update on this issue? Seems to me that the sign-in cookie expiry should be configurable in the AWS portal for a cognito instance, or per client configuration.
Any update on this?
Any updates??
Any progress on this?
any updates?
+1 for silent renew support on implicit grants
Sub'd, this is a deal breaker for using cognito user pools with SPA, would be nice to hear something from AWS.
AWS: please give us some sort of update on this issue? What workarounds can you propose for SPA apps, do you have any plans to deal with this? The silence is deafening!
I guess we'll have to use Auth0 again.
The typical process for refreshing tokens in an SPA is to call the OP's authorize endpoint with a prompt=none in the query string. This would normally occur in an embedded iframe in the SPA so as to not alter the UI and would either return new tokens which can be stored or an error, which deletes the tokens.
The iFrame flow does not work on the latest Safari. Auth0 warns about it here: https://auth0.com/docs/api-auth/token-renewal-in-safari
So I guess all we have left is
there is another option where we could have our own server which stores the refresh tokens and can refresh api/id tokens and deliver them to the SPA
I agree with @nihakue . After talking to AWS team we went with that solution - setting refresh token ttl to 1 day, and doing refresh token every hour with auth code flow.
@ppasmanik Can you please elaborate?
@sebastienfi
I believe they are using the Authorization Code Grant instead of the Implicit Grant to get a code that can be exchanged for a refresh token, storing the refresh token in the SPA, and refreshing the access/id tokens hourly.
Storing the refresh token client side in a web app would normally be considered very insecure however they have limited the lifetime of the refresh token to 24 hours, which is a tradeoff they have had to make as AWS provides no silent auth.
I guess the upshot is that users would have to authenticate daily rather than hourly.
@ravenscar Thank you for mentioning me - and for these clarifications!
@ravenscarhttps://github.com/ravenscar You are correct. The cognito-auth-js library provides various APIs to get refresh token, session, etc. It stores them in local storage. We wrote a small library that wraps amazon-cognito-auth-js and provides React components that know how to handle both types of the flows depending on configuration, perform refresh of tokens using oauth2/authorize endpoint of hosted cognito at configurable intervals (between 10 and 55 minutes depending on user roles). The minimum refresh token ttl is 1 day for cognito pool and it is sufficient for our users. You can set it to longer if you need. We also integrated idle timeout into that library that logs a user out after a configurable time interval.
From: Sébastien Fichot [email protected] Sent: Tuesday, April 23, 2019 4:39 AM To: aws/amazon-cognito-auth-js Cc: Pasmanik, Paul; Mention Subject: Re: [aws/amazon-cognito-auth-js] Refresh access and id tokens in a React/Angular SPA (#92)
@ravenscarhttps://github.com/ravenscar Thank you for mentioning me - and for these clarifications!
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/aws/amazon-cognito-auth-js/issues/92#issuecomment-485700128, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AA2674YCPIHPLQLU5RAIQXTPR3DKTANCNFSM4EROSASA.
The information contained in this electronic transmission is intended only for the use of the recipient and may be confidential and privileged. Unauthorized use, disclosure, or reproduction is strictly prohibited and may be unlawful. If you have received this electronic transmission in error, please notify the sender immediately. In order to make sure you receive our emails with the latest news on Dante, please add [email protected] to your contact list.