How can I protect refresh_token which generated by AWS Cognito for Single Page Application - amazon-web-services

I am planning to create a single page web application and all user authentication would be handled by AWS Cognito. By reading through some of articals, they all suggest using "code" grant flow + PKCE rather than implicit flow since implicit flow is deprecated in OAuth 2.1
I created a test user pool with AWS Cognito, by using Postman I successfully get access_token, id token and refresh token with code grant flow + PKCE.
I double checked with AWS Cognito Doc, seems refresh token will always be returned if using code grant flow and I cannot find anywhere in AWS console to disable returning refresh token. So just wondering how can I protect refresh_token? Cookie or localStorage can not stop XSS.

It is usual to route requests for tokens via a backend, eg a utility API, which also represents the refresh token as an HTTP Only SameSite=strict encrypted secure cookie. See this crypto code for an example.
The backend component also enables you to use a client secret, in addition to PKCE, which improves security a little. Cognito supports this, so I'd recommend using both.
BEST PRACTICE
OAuth for browser based apps recommends this approach. Stakeholders often expect you to be using the backend for frontend described, and it will make life more comfortable if you have to explain your app's security.
XSS
With the above HTTP only cookie approach, malicious code would not be able to steal your refresh tokens, and this is therefore the recommended way to handle them.
If your SPA has XSS vulnerabilities, then malicious code might be able to steal your data though, regardless of whether tokens or cookies are used to access data. Therefore it is critical to implement XSS protection carefully, regardless of your OAuth solution.

Related

How can you use the AWSELB cookies to also provide auth for your backend application?

So, I understand how OIDC works for the most part. I know how to solve this question if we use OIDC directly (without AWS handling it for us). The browser would just send their access_token to us for all async calls, and we could verify it against the OIDC UserInfo service that's hosted by our OIDC provider.
The AWS implementation doesn't expose any of these common OIDC values to the browser though, and just gives us their proprietary encrypted cookies like AWSELB. This is fine, for super basic sites where you don't care about actually authenticating the user once they're authorized, but we care about both.
We could also generate a proprietary "session key" when our callback is hit, and use that instead of the AWSELB cookie... but it seems like reinventing the wheel. Certainly, there must be a way to let our backend application code just reuse the AWSELB cookie to verify the identity of user? AWS documentation mentions no such webservice to allow us to validate that cookie from our server code.
The load balancer provides the IdP's access token as a header: x-amzn-oidc-accesstoken; you should be able to validate this against the IdP. It also provides user claims in a header: x-amzn-oidc-data.
See https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-authenticate-users.html#user-claims-encoding

AWS Cognito - verify token using JWT vs cognito.getUser SDK

I am using the following doc by AWS for verifying the incoming token with Cognito to verify the user in cognito pool:
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
Now I also need to verify one of the custom attributes (email) of that user. (Basically this is to mitigate a case where some user can change their email-id in the API payload to access someone else's details).
The Cognito SDK I found to do this was this : https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_GetUser.html
It works just fine, however this led me to a question :
Since I'm sending access token in this SDK, do I need to use the former jwt-based token verification as well? Because this SDK also handles the case where token is invalid/expired and sends error codes accordingly. Is there something I'm missing which the former case handles and the latter one doesn't ?
Short answer: no, you can ignore the contents of the JWT.
Longer answer: JWT tokens provide a fast way to verify that a user has been authenticated, without the need to check a database or external service. This can be very important in a high-volume application.
However, they have several limitations:
A JWT token is issued with an expiration timestamp. If you rely on the JWT, you do not have a way to forcibly log-out a user until that timestamp expires.
To be secure, your JWT token must be signed using an asymmetric keypair (I mention this simply because a lot of people have implemented their own identity servers incorrectly; Cognito does it right).
The claims that are in the token (and are signed by the identity server) may not be sufficient for your needs. Best practice is to minimize the size of the token, and iirc Cognito follows this practice by only including the user attributes that are directly tied to authentication.
If any of these limitations apply to a particular use-case (and it sounds like the third applies to you), then you'll have to make that external service call to the identity server. And if you do that, and the server reports authentication status, then there's no need to pay attention to the token.

JSON Web Token expiration and remember me functionality

I am starting to work on an authentication system for an angular 2 Single Page Application using django-rest framework as back-end. I'd also like to have some kind of "remember me" functionality that is going to keep users logged in for a certain amount of time.
From what I have read so far, it seems that the best authentication method for this kind of Angular 2 SPA/REST API is using jwt (json web token). For jwt authentication, I looked at the django-rest-framework-jwt (https://github.com/GetBlimp/django-rest-framework-jwt).
The problem that I see is that the token needs to have a short life span (few minutes to a few hours...) in order to minimize security issues if the token get stolen. The token now needs to be refreshed frequently to avoid the user from being disconnected while using the application. In this case, a "remember me" functionality is posing problem since the token have a short life span.
I thought about a solution involving a second token that would serve as a refresh token. It would be opaque, have a longer life span and would contain information specific to the user (ip address or something like that) so that if it get stolen, the information specific to the user being different would render this refresh token invalid.
So here are my questions:
1- I would like to know if they are existing solutions addressing this problem. As any security/authentication issues, I prefer to rely on well tested solutions to avoid getting my API compromised.
2- Would the refresh token based on specific user infos be a good idea?
3- Any other ideas how I could implement what I want?
For your situation, you really need a way to store issued tokens.
I always use an OAuth2.0 server setup that manages the auth and returns tokens the OAuth setup uses a database to manage everything so it's easy to manage and revoke tokens.
The database schema would be like this http://imgur.com/a/oRbP2 the problem with using just JWT without any management over the issued tokens with long expiration you have that security issue of not being able to revoke easily.
I would advise against including any such thing as a password in the JWT and requiring them to change it what if they use that password everywhere, then they would have to change that everywhere.
Updated from comments
Sessions Authentication use session_id which most the time is stored in a cookie and this is attached to every outgoing request. It is stateful. It is nothing more than a unique identifier that associates a user account that the server has in memory/database. For example, this can course problems when running multiple servers/instances when scaling your infrastructure.
Token Authentication no session is persisted on the server so this means it is stateless. It normally uses the header Authorization: Bearer REPLACE-WITH-TOKEN . This means that this token can be passed to multiple different servers/instances because the authentication is not limited to the server that you initiated the authentication on. This helps with scaling your infrastructure. Tokens can also be passed to other clients.
RESTful API's are stateless so there must not be a session state stored on the server. Instead, it must the handled entirely by the client so that's why token authentication is used.
I had the exact problem when trying to use JWT with an application that needed a lot more than JWT was designed for. OAuth2.0 has a lot more options that I believe are necessary to meet your requirement in the safest manner possible and even features that you may find very useful in the future as your Application may grow and need more features with regards authentication.

Can I use AWS User Pools as a directory service from a Spring app?

Is it possible to use AWS Cognito User Pools as an authentication and authorisation provider for a Spring Boot app running in EC2?
The user pools seem to provide a lot of the regsiter/login/email/forgotpassword etc plumbing, that I can make use of in an AngularJS front end.
If the front end does all the auth (in javascript), can a java (spring) backend verify tokens passed to it from the front end, and if so how?
Or, can/should the calls to Cognito come from the backend, and again, if so how? Do I need to use the AWS Android mobile SDK?
(I've looked at Lambdas and Api Gateways but they are not what I am after at the moment).
Either one of those options should work, depending a bit on your app requirements. The former does have the benefit of sending user credentials over the wire less often than the latter.
If you want to verify the tokens with your first suggestion, you could do one of a few things. Cognito vends an id token, a refresh token, and an access token upon a user authenticating. Any call that takes an access token (i.e. GetUser) does validation on that access token. Alternatively, you could make a call to refresh the tokens, which will do validation on the refresh token. More information on the tokens Cognito vends is available here. Token refreshing is done through the Cognito auth flow, using challenge name REFRESH_TOKEN or REFRESH_TOKEN_AUTH.
If you opt to go with the second one, AWS does have multiple SDKs for various languages, including Java. These all support the Cognito APIs, but Cognito does use SRP to sign users in. The client side calculations are fairly complex, so you might not want to take that on yourself. You could rip our calculations from the SDK on Github, or you could use the admin no SRP flow described here.

Which OAuth2 grant to use when dealing with a web based front-end

I have a backend running Django 1.7 and a front-end developed separately with Bootstrap. The front-end talks to the backend through a REST API that I want to protect with OAuth2.
The question is: which grant type should I use? I trust the people working on the front-end but it does not mean I trust Javascript :-) I can't decide whether I should choose the Implicit grant or the Resource owner password-based.
Any experienced advice?
Especially when working with an API that is not on the same domain or server as your front end, it's usually better to use something like the web application flow for OAuth 2. This is typically referred to as the implicit grant, and uses the grant_type of token.
This way you won't need to worry about sending credentials across the wire, like you would need to for the resource owner password credentials grant. Along the same lines, you also don't have to deal with hiding private keys for the authorization code grant.
With the implicit grant, only the OAuth token must be stored on the local machine. This should be better, as the token should be able to be revoked quickly in the event that the token become public or something else forces it to be invalidated. The user should be logged in on the API server when the authorization request is made, but most OAuth providers support a custom login page that can be used as well.
With the password credentials grant, both the username and password must be stored on the local machine which requires you to additionally secure them. They are also considerably more difficult to revoke if the need arises.