AWS Cognito - authenticate as a user - amazon-web-services

Our team has an app and we use Cognito for authentication. In previous projects, we were able to create sessions as a specific user, which helped us to debug issues.
Currently, our app consumes a JWT token for authentication needed by Cognito - would we be able to generate a JWT token for another user (as an admin) in order to debug problems within the app easier?

Tokens issued by Cognito are signed with private AWS keys and the signature within the token can then be verified using public AWS keys. If you could generate a token yourself, with a valid signature, then that would mean that you are in possession of the AWS private keys. I assume that that is not the case, so you cannot arbitrarily create valid Cognito JWTs.
You can of course write test code that ignores the signature or otherwise circumvents proper JWT validation.
Alternatively, as admin, you could create a Cognito user for testing with the properties that you wish to debug and just sign in as that user to get valid JWT tokens in return.

Related

How do I manage AWS cognito code grant flow on the frontend using the hosted ui

I would like to use Amazon cognito as a way to allow users to sign up to my app and validate api calls, so I don't have to handle user passwords or create a custom account recovery email system.
The problem is im not sure I understand how its supposed to work or what tools I am meant to use. Heres how I imagine it:
This way I could use cognito to identify users and authorize api calls.
But I am not sure if this is correct. For example I'm not sure if the frontend is supposed to refresh the tokens or the backend.
I am also not sure if I am meant to implement the code for exchanging and refreshing the token and logging out of users myself, but it seems that way since I can't find any tools that would do that for me.
I have found some libraries concerning aws cognito, but none of them mention exchanging or refreshing tokens:
https://www.npmjs.com/package/amazon-cognito-identity-js
https://www.npmjs.com/package/amazon-cognito-auth-js
https://www.npmjs.com/package/#aws-cdk/aws-cognito
I did find this library mentioned in the documentation that can be used to validate jwt id tokens on the backend.
https://github.com/awslabs/aws-jwt-verify
I am using userpools and no identity pools, since I don't grant users access to my aws resources.
So basically my question is, is my perception of the cognito workflow correct and if yes, how can I exchange the grant code for an id token and how can i use the refresh token to refresh the id token.

Difference between generating a token ID and authentication?

When a user signs up and provides a username and password and verifies their email address they can then log into their account which generates a token ID. Using that token ID in postman they can access the api. I thought this would be enough to validate the user. But what is the point of authorizers in aws?
For reference, code is similar to this: github
Am trying to understand why we need authorizers if a user can signup then login and generate the token ID and use that token ID to login. Isn't that enough to verify that the user is legimate? What does an authorizer further do?
I may be confused by authentication and authorization in aws. If I understand correctly, authorization just means the user knows the username/password and authentication is like an artifact like a cookie to determines that the username/password is coming from the original person who created that username/password?
Thanks
If you are talking about the authorizer on apigateway, then they are used to check if your token is valid. An authorizer checks your token against the resource, eg cognito user pool and make sure it belongs to that pool and isn't expired. If you don't have an authorizer and aren't verifying or using the token in your code at all then any person can pass a string in authorization header for API call and the call will go through.

AWS API Gateway authorizer google sign in

I have an API Gateway/lambda REST API that is being accessed from a react web app. I need to add authentication using google as an identity provider. The app should also keep the user signed in.
I understand when the user first grants access to the (react) client app, it should send the ID token to my backend, which should then verify the token.
Since my architecture is serverless, I assume the verifying should be done in the API Gateway authorizer function, which then grants access to the API on successful verification of the token.
My question is, how do I then create a persistent session? Should I be saving anything to my database about the user? Does the token need to be verified on every API call?
Should the authorizer be checking if the user is already registered or if it's a new user?
It would be easiest to use AWS Cognito for this. Configure a user pool as an authorizer for your API gateway and then configure Google as an identity provider for that user pool. This link might be helpful: https://docs.aws.amazon.com/cognito/latest/developerguide/google.html. Cognito even has a hosted UI if you want to use it for signing users in.
As for your question about persisting user sessions, they usually get persisted in local storage in the browser or in a cookie or some similar mechanism. You can also persist them on the server-side in a database like you were mentioning but that isn't really for authentication purposes.
The user session will contain an access token. The access token is short-lived, meaning you can only use them for an hour usually. After that you have to use a separate refresh token to generate a new access token. And to be extra safe the refresh token itself will expires after a few days (and you have to sign back in).

Is storing aws cognito JWT key in frontend javascript insecure?

I was reviewing a website's javascript files to find an endpoint i wanted,during this i found a line like this.
DASHBOARD_API_Token=eyJraWQiOiJVS2paTnB3SWdBK292QzB3RWdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
When i decoded the Above JWT i found entities like kid, username, useremail, iss = http://cognito-idp.us-east-1.amazonaws.com/{pool-id}
I have read few amazon resources which tell that its possible to fetch aws credentials using the above token. Given that i only have the jwt token what is possible and is it that i have to contact the website to revoke the current token?
Well, AWS Cognito is quite an interesting beast when it comes to its JWT tokens and what you can do with them.
Firstly, when you authenticate the user against Cognito User Pool, you get 3 different tokens: AccessToken, IdToken, and RefreshToken. Both AccessToken and IdToken are valid for exactly 1 hour (and you can't change it). This is why you get RefreshToken, which you can use to get new pair of AccessToken and IdToken by calling, for example, InitiateAuth. RefreshToken is by default valid for 30 days, but you can change it in the settings of your Cognito User Pool.
AccessToken
This is the most powerful token that is given by Cognito. If you possess a valid AccessToken, you can call several quite sensitive Cognito APIs.
One very surprising example is that you can call DeleteUser API by providing AccessToken and it will completely remove your account from Cognito User Pool. The "nicest" thing here is that app developer can't stop you from doing it if you've got a valid AccessToken. AWS devs are saying that "its by design". That was one of the strongest reasons why we decided not to pass Cognito Access Token onto the application frontend.
Speaking of the payload of AccessToken, the only potentially sensitive claim is the client_id, which contains the Cognito Client Id, which was used to authenticate the user. If this client does not have a client secret (which should probably be considered a security flaw in the first place), then the client_id can be used to call quite wide range of Cognito APIs. However, Cognito considers client_id to be public information. All other claims are considered public, you can see the full list of claims here.
IdToken
Contains the information about the player. It may contain some personal information about the player depending on what standard claims and custom attributes were configured in your Cognito User Pool, however it is also possible to suppress or override those claims using Pre Token Generation Lambda Trigger. Using this trigger allows one to hide or mask player attributes, which are considered sensitive and should not appear in IdToken.
As far as I'm aware, you cannot user IdToken to call Cognito APIs.
RefreshToken
Can only be used to request new AccessToken and IdToken, cannot be used to call Cognito APIs. In our particular use case we had to avoid passing RefreshToken to the app frontend, since it can be used to get AccessToken against public Cognito API (meaning that we cannot stop the user from doing that).
Using Cognito tokens to get AWS credentials
This is only possible if Cognito User Pool has been explicitly integrated with Cognito Identity Pool (which assumes that app developers knew what they were doing). When you exchange your Cognito JWT tokens, you get temporary AWS credentials with permissions bounded to a specific IAM role configured in Cognito Identity Pool. It is completely legitimate flow and intended behaviour. Moreover, if Cognito Identity Pool is configured to allow unauthenticated access, you can even get temporary AWS credentials without having Cognito JWT tokens (but those will be tied to another, presumably, more restrictive IAM role).
Using Cognito tokens with API Gateway
AWS API Gateway resources can be integrated with Cognito User Pools. Depending on how the integration is done, you can use either an AccessToken or IdToken from the integrated Cognito User Pool.
Revoking the tokens
You can revoke all tokens issued for your account in Cognito User Pool by calling GlobalSignOut API and providing a valid AccessToken. As this API is public, you don't need to contact the website if you possess a valid AccessToken.

AWS Cognito federated identities + permanent access key for programmatic API

I have an API service, which I'm going to deploy using AWS API Gateway with Cognito authorizer + Lambda as backend. This service will be used by our javascript client. Also, it should be exposed to end users as raw endpoints for programmatic access.
While it was quite easy to enable signup/login in js client using federated identities, I can't figure out the way to provide users with private access token to include directly in http headers.
Here are two authentication flows, I'd like to get in the end:
The flow for js client user:
User signs up with Facebook or Google.
User verifies his identity.
After login, user goes to the Profile/API Keys section in the interface.
User copies access token and can include it in http request header in any http client (httpie, curl, language libraries whatever)
The flow for admin created user:
Admin creates user.
Access token is generated for that user.
Admin passes generated access token the user.
User can include it in http headers to make request, as in previous flow.
An access token should be permanent, and can be regenerated by user at any time (think of Stripe API access keys).
The point here is to eliminate additional steps for the user to start using service programmatically. The closest thing in AWS docs so far is developer-authenticated-identities, but user should utilize AWS sdk anyway.
One possible way to accomplish this task is to use Custom authorizer instead of Cognito authorizer in API Gateway. Custom authorizer could implement logic based on e.g. auth header name and decide to either authorize in Cognito or to user API access token in database. I'm not sure, if it is possible, and if it is the major drawback is to reimplement Cognito authentication flow in lambda function.
The question is how can I accomplish such API access token (re)generation using Cognito or API Gateway?
The first flow should be possible with User Pools. Cognito User Pools now has a federation feature where you can federate using Facebook/Google and receive access token/refresh token depending on the flow used.
For admin created user, the user would need to authenticate before tokens are issued but this can be achieved by creating the user with a temporary password and signing the user in with that password, after which it can be changed and logged in again to receive access/refresh token.
The refresh token use case is that it can be used against the Cognito APIs to receive a new access token. When the refresh token expires (default is 30 days but it is configurable), the user would have to authenticate again.