amazon-archives / amazon-cognito-identity-js

Amazon Cognito Identity SDK for JavaScript
Other
984 stars 454 forks source link

Refresh access and id tokens in a React/Angular SPA #689

Closed ravenscar closed 6 years ago

ravenscar commented 6 years ago

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

ravenscar commented 6 years ago

apologies, I meant to post this in the aws/amazon-cognito-auth-js repository instead.