Should I store the cognito auth token in my database? - authentication

I have a mobile application which needs to be GDPR compliant. We're using AWS amplify and appsync, but we're unclear on how the Cognito auth token is used. Do we need to store the token in our database to associate it with users?
Our concern is that once a user is authenticated, the client will not know which userdata is associated with that identity unless we store the auth token.

You don't need to store tokens. Cognito Auth token are JWT tokens. JWT tokens can have custom payload within them. Everything you need is already included in it. You can pass literally anything like userId, phoneNumber etc... any custom data when you are issuing the tokens.
For example, if you trigger lambda with apigateway and use cognito pools for authorization you will automatically get sub etc in the claims field which you will identify user in the client (in this case client is lambda)
If you are using custom lambda authorizers you can still use cognito user pools but this time you are absolutely free to embed any custom data into token to use it later.
Play in jwt.io with your tokens and you will see whats in it already.

Related

Can I federate Cognito with "client credentials" flow (or other way to trust a server-side application authenticated elsewhere?)

I have an AWS REST API Gateway with Cognito authentication using the client credentials grant.
We have been creating new clients by hand and sharing the ID/secret with people who need to use our API. They send the ID/secret and "grant_type=client_credentials" to Cognito, it gives them a bearer token and they use the API with the token. All fine so far. (It is a CLI tool running on a schedule, not accessed by a browser. I specifically need to avoid any sort of "go to the browser to login".)
Now, we have a new "island" of users who have a local OIDC (Azure AD) provider that can issue them a bearer token from a curl to an endpoint.
Is there a way to make Cognito accept those tokens??
I have tried federating Cognito with a different oidc provider (I don't have AD, but a different provider), getting myself a bearer token from it and sending it to the API GW, and I just get 401'ed. I don't know if there is something I'm doing wrong or if it's not possible.
(Things I might be doing wrong seems to be a long list! I need to create a client in the other provider and add it's ID/secret/URL to Cognito, that works. I used the same client ID/secret to generate my bearer token. But when I'm in client creds flow in Cognito, I need to set a custom scope. Do I need to add that scope to my initial request to the other provider (The API GW doesn't require a scope, it is just a mock endpoint at the moment in testing). The client_id= in the request is for the client in the other provider, not the Cognito client ID. Should I set it to the Cognito client ID?)
OR do I need to write a custom authenticator for the API GW to validate the token? (Decode JWT, Check : issuer is allowed and signature is valid.)
And not use Cognito at all for these other users.
(If it was an HTTP API, I think I can create a JWT authoriser and it does it all for me, but it isn't and there are some features on REST APIs not available on HTTP (like WAF))
Sorry it's a bit short on details. I could spend days copy/pasting all the configs from ID provider/Cognito but if it fundamentally won't work I wasted my time!
(After trying it, I think maybe federation only works for actual users with a browser based login flow, not clients with a CLI flow. I can't find anyone saying client credentials flow does work anyway!)
Cognito is using the authorization server role. So in all cases, the tokens returned to client applications will be issued by Cognito. These apps will never deal with Azure AD tokens. Multiple types of client can coexist together:
CLIENT CREDENTIALS GRANT
Clients who use this flow might represent B2B connections. The business partner must always get Cognito tokens directly, and no federation is used here.
AUTHORIZATION CODE GRANT
Browser clients will use this flow, and you can configure Cognito to implement authentication by making a second OIDC Connect redirect to Azure AD.
My blog post provides a walkthrough on how settings are configured. Cognito will act as a client of Azure AD and use a scope such as openid profile email.
After a user login, Cognito will receive Azure AD tokens, validate them, then issue its own tokens. Nothing will change in the API gateway, which will continue to verify Cognito tokens.

Why shouldn't I use IdToken as bearer token in an IDP context?

I am using an IDP platform (here AWS Cognito but that could be Auth0, OKTA or Keycloak) and I was wondering why I was discouraged to use the ID Token as an authorization token.
To be more specific, I will not make use of a resource server with authorization delegation from a user to a third-party app. My IDP will just let me SSO all my users on my different applications. There is no scope to grant here, only authentication claims that each service will use to grant or refuse access to resources (like an email, user ID, or the roles).
I understand I could provide my application with the id token and then create some session for my user. By why shouldn't I use the id token itself as a stateless session token, given that its signature can be checked on each application's back-end ?
And if I should use an access token over the id token - can I replace scopes by roles ? Or how should I understand the scopes in a non-delegation context ("user is usign the app himself, not giving permission" vs "user is giving all scopes to the SPA front-end which is an application in itself")
By the way, I am recovering the tokens through code PKCE flow on the front end.
The ID token only contains details about the user and how the user authenicated. so its perfect for creating a longer lasting cookie session with the user. The default lifetime for and ID-token is very short as well, like minutes. You typically throw the id-token away after establishing the sesson. You should never ever pass the ID-token around to other services.
The access token is mean to give you access to the APIs that the token is intended for.
when the user signs in, you ask for acceess to certain scopes and the scopes selected (consented) by the user , then is included in the access token (as scopes and audience claims).
In theory you can pass the ID-token to an API, bits not how its supposed to work.
See this and this for more details:

Manage Cognito User Pool using JWT

I have a Node.js lambda API that's called by an authenticated user. The user is able to access the API passing a valid JWT token. Now I'd like to interact with Cognito User Pool to change the user's email, password and etc but I haven't figured out how to achieve this using just the JWT.
I've made several tests using amplify-js and amazon-cognito-identity-js
You can reset the user's password by calling an admin API call, not through the JWT token. https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminResetUserPassword.html This will prompt the user for a new password.
This API call is to set a password for that particular user https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminSetUserPassword.html but I prefer the first option.
In order to change user attributes (such as email, birthday...), use https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminUpdateUserAttributes.html
So all these are done using the Cognito Service inside the Lambda (not to be confused with the JWT tokens).

Is there a way to immediately revoke a Cognito Client Credentials Flow issued access token?

AWS Cognito has API methods GlobalSignout and AdminUserGlobalSignout that can be used to revoke the access and refresh tokens issued for a user in a user pool (but not the ID token). However, the access token issued using the client credentials flow has no associated user. GlobalSignout fails with an error and AdminUserGlobalSignout requires a username, of which there is none in this context.
The token is short-lived, but in a situation where access tokens have been compromised, revoking the token in a way similar to that described in RFC 7009 would be great peace of mind.
I haven't found anything indicating it is possible to explicitly revoke the token before it expires. Is there any facility to do this?
Maybe one day Cognito will have this and other essential features but it is not for today. The best advice is to validate tokens in your authorization code.
When you are ready to revoke a user's tokens, make a call to CognitoIdentityServiceProvider.globalSignOut().
Then, wherever you are doing the token validation, add an extra check with a call to CognitoIdentityServiceProvider.getUser(). If the call succeeds, the tokens haven't been revoked. If it fails, they are not authorized.
By the way, the 'sub' field in the Access Token is a unique ID that can be matched back to the ID Token. While the username can change for a Cognito User, this value should remain constant.

AWS Cognito - Why is token still valid even User pool is changed or User is deleted (.Net core)

I'm quite new to AWS Cognito and about token security. I decided to use AWS Cognito for may application. I followed the guide here for my web app and my web api.
https://dzone.com/articles/identity-as-a-service-idaas-aws-cognito-and-aspnet
https://dzone.com/articles/identity-as-a-service-idaas-asp-net-core-api-and-a
Everything works fine. But when I try to create a new User pool in AWS Cognito and then change the appsetting for both web app and web api to use the new user pool, I found something quite weird.
(For the web app). User still can access controller action by the old token that belong to the old User pool that used before even the action is marked as [Authorize]. I don't know why user still can access with the old token even appsetting is set to the new User pool. (But User cannot access to the web api,that use new User pool, with the old token)
(For both web app and web api). Then I deleted that User from the old User pool and set web app and web api to use the old user pool. I found that User still can access both action in web app and web api even that User was deleted.
I think that it might be something that I missing about validation token or setting. Can anyone suggest about a solution to fix that?
The ID Token issued by AWS Cognito User Pool is a JWT token, which is Signed By AWS. Once issued the token is valid for 1 hour. Within this 1 hour, there is no way of revoking the token since its stateless.
Amazon Cognito generates two RSA key pairs for each user pool. The
private key of each pair is used to sign the respective ID token or
access token. The public keys are made available at an address in this
format:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
Since the public key is publically available, anyone can verify whether the JWT token is authentic and issued by AWS Cognito.
However, this involved multiple things to verify.
Validate the JWT Token Encoding whether its compliant with JWT standard.
Validate JWT Issuer, whether its the particular User Pool (Verify its ID).
Validate whether the token is an ID Token (Optional).
Validate the Audience of the Token (Whether it is issued for the particular App).
Validate Token Signature (This is where the public key is needed).
Validate whether the token is expired or not.
This information is already self-contained within the JWT token string properly encoded according to the JWT standard.
Therefore, even the Cognito User Pool is deleted, if there is a valid token (< 1 hour after issued), it should be valid, if the verification process uses a stored Public key to verify it.