AWS Cognito Identity Pool: AWS Credentials Expiration / Renewal - javascript

I'm building an AWS-backed site which, broadly speaking, does the following:
Authenticates a user against a Cognito User Pool (the pool is backed by a third-party SAML provider), giving them tokens.
Uses a Cognito Identity Pool to grant the user credentials for use with other services.
Lets the user perform a series of long-running S3 uploads, directly from the front-end S3 client, using the credentials from above.
I'm trying to get clarity on the interactions I will have to have with tokens and credentials. I'm pretty clear on what I have to do with the tokens I get from the user pool:
I can use them to call the Identity Pool, and get AWS credentials I can use for S3.
I can use the refresh token to refresh the other tokens if they expire before I'm done.
The expiration details for these tokens are in the link above. The documentation is pretty clear on all of the above, but I'm confused about the Identity Pool credential functionality, and haven't been able to find explanations in the docs on the following questions:
When I get AWS credentials from my Identity Pool, how long will they last before expiring? How can I configure this value, so that my CognitoIdentityCredentials gives me credentials with my desired expiration?
If my AWS credentials expire before I'm done with my work, what's the right logic for attempting to 1. refresh the credentials and 2. if that fails, refresh the user pool tokens, so as to be able to complete the operation cleanly without making the user restart it?

The user pool is only for user management. Any interaction that the user has with AWS services and resources is done via Identity Pool. You assign the roles via Identity pool.
To answer your 2 specific questions:
Tokens last for 1 hour. This duration is fixed and cannot be changed.
If your tokens expire you can use the refresh token to generate new identity and access tokens. However, most of the front end sdks (even javascript) do this automatically for you. You don't have to worry about tokens expiring. In fact you will have to forcefully invalidate them if you have that requirement.

Related

Serverless Discord OAuth Method

I want to create a serveless login system with Discord OAuth. There are two ways I can think of doing this which are written below.
My questions are as follows: Am I barking up the wrong tree with these two potential methods? If either of the methods are suitable which would you go with? Is there a much better way of doing this?
User signs in with discord and an access token is provided
The access token is stored in a database along with the username and user ID
Session Cookie
The user is provided with a session cookie containing a user ID and session token. Each time the user needs to authenticate the session token is checked against the session token stored in the database - this requires calls to the database each time a user needs to authenticate which could potentially make things very slow.
JWT
The user is provided with a JSON web token every time a user needs to authenticate a serverless function is used to check that this token is valid and has not been tampered with - this comes with it's own security problems such as difficulty to implement token invalidation

Google Identity Refresh Token (Web)

Per https://developers.google.com/identity/sign-in/web/server-side-flow in order to get a refresh token, the client must grant offline access. However, I see no way to do that using the new API. What's the proper way to get a refreshed token using the Google button, so the user doesn't need to re-login every hour?
Authentication for sign-in has been separated from authorization for data access in he new API.
In the new API authentication does not require or use access or refresh tokens, instead a signed JWT ID token credential containing the user profile is shared after user consent. This greatly simplifies the level of effort and need to manage tokens during app sign-up or sign-in.
If you're performing authorization to access Google APIs and storing refresh tokens on your backend, then a server-to-server OAuth flow is appropriate.
Another clarification, user sign-in to your app and maintaining session state are separate concepts and should be handled separate from backend processes which may use an offline refresh token to perform actions through a Google API on behalf of the user while they are not logged in.

Destroy JWT token, force logout when user gets banned or edited

Good day friends,
I am developing an application, in my user system add the functionality for administrators to raise the level of the account (if level 10, it's admin) or ban it from the site.
Once the user logs in, he receives a token that contains information about the level of his account, whether it is banned or not.
This function works perfectly, but if the user is banned, they can continue using the site until they receive a new token or it has expired, since the information is acquired from the token. I want to force the user to close their session (destroy JWT token) once it is banned or its level has been edited.
I can verify in the routes that every time the user makes a call, the backend checks in the database if the user is banned or not. But I would like to simplify this step so that the server does not make so many calls to the database. It occurs to me to remove the user's specific token or make it invalid once it is banned from the site or its level has been altered. So the user is forced to log in again and get a new token.
Is there a method or library that makes it easy for me to remove the tokens or make them invalid?
Because if i enter with my admin account and try to edit my account and give it a level 1, i should not be able again to edit this user because my lvl is 1 and i need lvl 10 again for using this route functions, but i can edit it again because token authorization is valid and that shouldn't happen
I want to force the user to destroy their JWT token once it is banned or its level has been edited.
This is not possible, a user can retain any data you've given them.
The best solution you can get with tokens would be to have a very short expiry for their access tokens, and verify the blocked status and level every time you create a new one for them. If a few minutes of lag is acceptable to you, this is the way to go.
Is there a method or library that makes it easy for me to remove the tokens or make them invalid?
You are looking for plain HTTP sessions. You would not hand out any signed tokens with the data at all, you would store the session data on the server side - in ram, an extra cache, or a database. From there you can purge it to invalidate the session and log out the user, or change their access status.
There's a standard implementation for about every server ecosystem. Don't implement this yourself with a database request on every route, use a middleware solution like express-session (see How to use session variable with NodeJs?).

How to authenticate user in browser using AWS Cognito?

I need to authenticate users in browser (not mobile app) using AWS Cognito with username/pass, not FB/google IdProviders.
There are a lot of docs but they seem to be separate blocks which either incomplete, do not fit the requirements or do not fit each others :(
I created Cognito User Pool, then Identity pool and tied the userPool to the idPool, then I stuck. Do not know which library to use and how to use it.
The closest I find are:
https://aws.amazon.com/sdk-for-browser/ but my experience is not enough to convert their FB samples to not-using FB
https://github.com/aws/aws-amplify but using this lib I'll have to study React/Angular from the very beginning (I'm not a front-end developer, sorry) and I have no clue how to convert their npm-based samples to front-end javascript (npm is for NodeJS thus back-end, isn't it?).
All I need is plain html form with username/pass, send the request to Cognito and a way to check during the next page load whether the password was correct. If it matters I will use AWS Lambda as back-end for processing future tasks.
How can I do it? Is there a tutorial/doc for my case?
Thank you.
You can use AWS Cognito UserPools Hosted UI for your use case. The simplest form of authentication is using the Implicit Grant.
For more information about setting up Hosted UI refer Add an App to Enable the Hosted Web UI.. This will create a UserPool where users can register them self (If you plan to restrict this, you will need to either add users using the AWS Web Console, Cognito UserPools or using their SDK)
The steps are as follows.
Set up Cognito Hosted UI and register your application domain. This will create the login/registration pages for you where each of this will have a unique URL. What you have to do is, if the user is not authenticated (Let's discuss how to detect it later), you need to redirect the user to the Login page.
In the Login URL, you also need to specify the redirect back URL to the application so that after a successful login, Cognito will redirect back the user to the application providing the token in a query string.
You can then access the id_token from inside the application and use it for querying the backend.
Since the id_token is a JWT token you can verify it at your Backend using the public key available at the Cognito token endpoint.
To implement the JWT verification, you can also refer Cognito JWT Token validator NodeJS module.
Note: If you need to keep the user's logged in for a longer time period (Than 1 hr), you might need to use the Code Grant flow which will return a Refresh Token, which could be used to retrieve new id_tokens programmatically.

Handling JWT expiration and JWT payload update

I have a Koa based Node.js backend for my personal/hobby application.
I implemented session handling with JWT tokens. The client (AngularJS) gets the token after a successful login and stores the token somewhere (currently in sessionStorage but for the purposes of this question it shouldn't matter).
I have two questions:
When I need to update the user record which the JWT represents, say, the user turned on Two-factor authentication (2FA) so I asked him to provide his phone number and I'd like to set this phone number in the user's record. Currently, after a successful verification on the phone number I call my backend to update the user record and I create a new JWT token with the updated user record (I exclude sensitive information from the JWT token like the hashed password, but I'd like to include the phone number for client side usage). Is it okay to create a new token when some of the credentials change and update the existing client side token with this new token? Should I never-ever create another token, only to create the one and only upon successful authentication? How do I then update the payload in the token?
How should I handle expired JWT tokens? In my mind I have 3 (possible) scenarios:
2.1. The JWT is set to short living, say 15 minutes. If the backend server replies with a 401 Unauthenticated 'Invalid token' (I guess this is the default behavior of koa-jwt) then I automatically log-out my client and require re-authentication. But I also set up a complementary middleware, which is the last in the chain on the backend to re-create the token with a refreshed expiry and the client would also replace the existing token with the refreshed one. So if the user is active and uses the application every protected API call, in case of success, would create a new token to replace the old token.
2.2. The JWT is set long-living, say 1 week, and if it expires I opt-in re-authentication from the client.
2.3. Copy https://www.rfc-editor.org/rfc/rfc6749#section-1.5. Here when creating the JWT token after a successful authentication we send an access_token as well as a refresh_token. When the access_token is expired and the server responds with HTTP 401 'invalid token' (koa-jwt default) then the client sends the refresh_token to the backend to require a new access_token (and optionally a new refresh_token). In this case I don't fully understand how the refresh_token is verified against the old access_token to provide a new token? Or why do we need to have a refresh_token?
Any generic advice on the upper topics (JWT updates and JWT expiration) would be helpful.
Starting from the bottom, I would ignore refresh tokens as I don't think they will help you here. They are generally aimed at other scenarios where the client application can provide storage more secure than the user browser -- think native mobile applications or server-side web applications.
Refresh Tokens are long-lived. This means when a client gets one from a server, this token must be stored securely to keep it from being used by potential attackers, for this reason it is not safe to store them in the browser.
(emphasis is mine; source refresh tokens)
This means that option 2.3 is basically the same as 2.2, which is not a bad option. It's not uncommon to have web applications with long session duration. If your application is not highly sensitive it's acceptable to use long session to improve user experience. For example, Django uses a default of two weeks for the age of its session cookie. See SESSION_COOKIE_AGE.
The remaining option (2.1), is usually referred as sliding session. The session timeout is short, but as long as the user keeps using the application within that interval the session gets automatically renewed. This is possibly the most common approach, or at least the one I used most time, so I'm biased. The only thing I would note is that sliding session are usually implemented with opaque session identifiers stored client-side as cookies and then with the actual session data stored on the server.
Your approach is a bit different because you have a stateless JWT token (it contains actual user data) stored on browser local storage. Like you said, in order to update the token you'll have to generate a new one, because you'll have to generate a new signature.
The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn’t changed in the way.
(emphasis is mine; source JSON web tokens)
Having said all that, I would consider the following:
Ask yourself if you really need JWT's or if regular session identifiers stored as cookies (HTTP Only) would simplify your logic.
If JWT's are a requirement, for example, you have another API that will also accept these tokens as authentications, then I would consider option 2.1 or 2.2 as refresh tokens for a browser-based application are not recommended.
Having said that, you should also consider that JWT's are not huge, but they will still be an overhead if you decide to be automatically renewing. You may mitigate this a little by choosing a session duration of 20 minutes and only perform automatic renewal after half the session has elapsed.
Another point is that a vulnerability like XSS in your application will expose the access token to an attacker as the injected scripts would be able to read from localStorage/sessionStorage, this can be another point in favor of HTTP only session cookie storage.
I would like to answer your second question before I can get on to the first one.
Basically the third option which you have mentioned is the best way to renew your access tokens. Access token should be short living(~5mins) and refresh token has longer life. When your access token gets expired, send your refresh token to the backend and get a new access token. So your response should be something like this:
{
"token_type":"bearer",
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiVlx1MDAxNcKbwoNUwoonbFPCu8KhwrYiLCJpYXQiOjE0NDQyNjI4NjYsImV4cCI6MTQ0NDI2Mjg4Nn0.Dww7TC-d0teDAgsmKHw7bhF2THNichsE6rVJq9xu_2s",
"expires_in":10,
"refresh_token":"7fd15938c823cf58e78019bea2af142f9449696b"
}
So the idea is to seperate your application into Authorization Server (which generates access token / refresh token) & Resource Server (validate access token and access the resources ). You can maintain a schema to validate the refresh token against the access token in Authorization Server. Please refer to the schema section mentioned in this link which might give you some idea. Oauth2. You can modify the schema according to your need. You need not send your refresh token along with your access token for each request call. Refresh token can only be sent to Authorization server for generating new access token. How to generate refresh tokens? If I am using Java, I would use UUID.randomUUID() to generate a unique refresh token.
Now to answer your first question, if you want to update your JWT payload based on your updated user records, then you can use the same refresh token to generate a new access token with the updated payload. The logic remains same because if phone number exists in the user record it gets added to the payload and if not, it will be null in the payload.
The main advantage of using Refresh token is that the Access Tokens can be renewed at any time using Refresh Tokens

Categories