I am using AWS Cognito in my application to authenticate users. AWS provides us with JWT token. My question is do we need to use express-session for handling session management, or will the JWT token provided by AWS Cognito take care of session management for authenticated users.
When you use Cognito JWT tokens, you don't need an explicit session handler.
You can send the JWT token to the client side and store it in the web browser (Local storage, Session storage or Cookie) which provides the persistence of the state(Acts as the session and will be valid for the token duration).
For all the subsequent requests you need to send the JWT in authorization headers back to your express server.
This is will have advantages over the sessions where if your API is consumed by clients other than web browsers such as mobile apps where it enables to implement unified state management.
To minimize the risk of storing id tokens in the LocalStorage for applications that requires high security, make the token duration small and generate new tokens using a refresh token.
Note: You will need to use Cognito Autorization code grant flow to get the refresh token if you use the Cognito Hosted UI .
Related
I'm building a REST API and using AWS Cognito's user pools for authentication. I've got a "get_token" endpoint that returns the JWT access and refresh tokens to the user, which they use to authenticate access to the other REST endpoints provided by the API.
The access token has an expiration timeout. If the user of my API is an application program, what are the best practices for the application to handle when the access token expires? Does the application have to remember the username/password and re-authenticate to continue? Is using the refresh token to get a new access token and use that going forward the best approach?
Is there any documentation, suggestions anyone can point out that might help me out?
Cognito provides 3 types of tokens, id, access and refresh tokens when you login. The way this usually works is that you send either of the first two (depends on whether you want to be sending user payload information to your backend) to your backend via an Authorization header and verify the token there.
Your id and access tokens usually have a shorter expiration time compared to the refresh token. What you should do is, when the id (or access) token expire, you should use the refresh token to generate a new id (or access) token. When the refresh token expires that means that you can no longer generate new id/access tokens from it. In this case, the user (or app) must login again.
Consider:
An SPA or a statically generated JAMStack website (written in Vue/Nuxt).
A REST API (Node + Express) running in the cloud.
The website is being served through a CDN.
We are required to add a Social Sign-On functionality for user convenience. The API already authenticates users with a credential based JWT (access/refresh) token flow. Social sign-on will be in addition to that.
We have selected the Authorization Code Flow as the mechanism for this implementation (instead of PKCE, because we want the SPA to use the API's access tokens instead of the authorization provider's).
Our flow is as follows:
The user clicks on a button and is directed to the Identity Provider's (in our case, Google) website to prove its identity. We provide a randomly generated state token as a request parameter to prevent CSRF attacks.
On the IdP's authentication page, the user submits their credentials and if successful, the user is redirected back to our website (the SPA) with the state token and a code as url parameters.
We then match the state value with the one that we generated on our app to defeat CSRF attacks.
We send the code value to our API in an AJAX request.
The API takes this code and our client secret and exchanges them for an identity taken with the identity provider (disregarding the access tokens as we only require proof of identity).
If the user identity is verified, the API generate a pair of access and refresh token and sends them to the SPA. (If the user does not exist in our database, it is added and similarly returned tokens for our API).
NOTE: We do not store the identity token received from the IdP on the server at all.
One receiving the response, the SPA stores the access token in localStorage, (the refresh token is stored in an HTTP only cookie by the API).
All further requests to our API from the SPA are made with the access token issued by our API, once both the refresh token and access tokens expire (through logout or timeout), the user has to re-initiate the authentication flow from step 1.
I have two questions:
Assuming that all communication between the IdP and SPA, the SPA and the API, and the API and the IdP is happening over TLS, are there any security vulnerabilities present in our process?
This one perplexes me more, how do you persist the state token that we generate during the initial request to the authentication server between page redirects? (from when we leave our SPA to authenticate on IdP's webpage to when the IdP redirects us back to our SPA). Is localStorage a secure enough option? If not, would sessionStorage suffice?
For a new project I would consider using the BFF pattern to avoid dealing with tokens at all in the SPA/browser. Because there is no secure way to deal/store tokens in the browser.
Do check out these resources for more details about why this pattern is recommended for new projects:
alert‘OAuth 2 0’; // The impact of XSS on OAuth 2 0 in SPAs
Using the BFF pattern to secure SPA and #Blazor Applications
The BFF Pattern (Backend for Frontend): An Introduction
Im playing around and creating a custom access token system using JWT. I have already created a system for signing and validating JWT access tokens.
However, I find it hard to obtain information about what claims a refresh token should consist of.
Should i create refresh tokens identical to the access token - with a longer expiratiom time so that the same function that validates access tokens can be used to validate the refresh token?
A refresh token is typically an opaque value that is only used by clients to refresh access tokens. The flow works like this:
Web or mobile client implements OpenID Connect to authenticate users and get tokens - prompting the user to consent in some cases
An Authorization Server (AS) issues the tokens and stores details of this 'delegation' in a database - tokens are a pointer to this state
Client sends access tokens to APIs until a 401 expired response is received
Client then tries to refresh the access token by sending the refresh token to the Authorixation Server, which then looks up claim details from the stored state
I would make sure you get these responsibilities right - in particular avoid building your own AS and use a free one provided by experts, such as Curity Community Edition. Many security solutions will then be easier to develop.
I created a single page application (SPA), which relies on GitHub API v4.
The API requires an access token to access, so I created an input element to ask users to store their access token.
I want to persist the entered token so that users don't re-input the token after reloading or re-visiting the site, without building any backend server.
I tried few things to achieve my purpose:
save the token in localStorage
It is very easy, but there are security concerns to store secret information in the storage, so I rejected this approach.
use GitHub OAuth App to fetch tokens
It is not suitable because it requires to store client secret in my app. Since my app is SPA, the stored secret can be read by any user.
use Auth0 to bypass the authentification
At first, it seemed very easy to get GitHub access token, but it requires a backend proxy server to fetch the token as described here
Is it impossible to persist the token without any backend server?
If so, how to persist the token easily? For now, I came up with the below solutions:
use AWS Lambda to encrypt the token and save it into cookie
When users input the token, the app send the token to a Lambda function, which encrypt the token and response it into cookie. When users back to my app, the app send cookie to the Lambda function and decrypt the token and send it back to the app.
use AWS Lambda as a proxy to communicate with Auth0
As described here, Lambda functions can retrieve the GitHub access token via Auth0.
However, I don't want to do this because I don't want to use two external services just to persist the token.
We have legacy applications in .net framework which have their own separate authentication mechanism going through the database to validate credentials and generating an access token. Now we are trying to use Identity Server to generate an access token , and trying to implement single sign on using this token.
Since all our client applications and api resources are in house, we intend to share this token amongst all our applications.
The web app where user logs in passes the credentials to a rest api. The rest api then talks to IDentityServer4 (using resource owner password grant) to authenticate and get an access token . This token is returned by the rest api to the web app, which then passes it to another web app , which then tries to access another streaming api . The streaming api now needs to validate the token with IS4 , and then allow access to web app2.
The problem we are facing is that :
1) the access token has a limited validity period , after which it will be invalid. The web app2 cannot refresh the access token , as only the initiator of the token ( rest api) is allowed to do that .
2) Even if the rest api takes care of refreshing the access token when its about to expire by using refresh token, a new access token is granted which is not the same as the old token which was shared with other clients. Is there any way for the web app2 to keep the token alive which was initially granted to the rest api.
I have tried refreshing the token on web app2 , which fails as it is different from the client who owns the token.
I am aware that this is not the best way to use IS4 , and ideally the client apps should be talking to IS4 and authenticating through IS4, and also getting grants to access the api and identity resources , but since we do not want to change all our applications at once , we are trying to make the api resource talk to IS4 to generate a token.
Is there any way to keep the same access token alive until revoked by the initiator client ?