Cognito User Pools & Access Tokens - amazon-web-services

I am hoping to use Cognito and User Pools to support a multitenant environment. So far it checks most of the boxes. It is my understanding that there is no current way to enrich the access token using Lambda triggers. I would really like to pass something to identify which user pool the user authenticated with in the access token to my APIs. Am I missing something or is there a workaround for this?
One option that came to mind is to create a group in each to which all members of the pool are members off that is either the name or combination of the name and tenant id. Is this a reasonable approach or a horrible idea? something like tenant_1234. Then I believe this group would be included in the access token and can be parsed to get the id.
Thanks.

I may had misunderstood the question, however access token payload contains the user pool Id https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-access-token.html#user-pool-access-token-payload
Issuer (iss)
The iss claim has the following format:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}.
You can also add the custom scopes to the access token to customize the payload further

Related

AWS Cognito: Why do you need an ID Token? [duplicate]

Just reading the docs, they seem very similar to me so I can't really discern why to use one over the other. Although identity token seems better since it has custom attributes on it from the user pool (eg: custom:blah and the default ones like name and email).
Right now, I am working with an app that passes the access token back down to the browser so it can use it for making ajax REST calls (there is an auth filter that expects this access token and validates it). Could I just switch out the access token with the id token? The current validation logic is to just get the sub field (the uuid) from the access token, but this sub field is also present in the identity token (as well as practically every other attribute except the aud which I don't need). I just want to make sure I am understanding this right as it is confusing to me why both tokens exist and seem so similar.
The id_token is for your application to process, so you can get all the personal details for your user, like their name, age, email address etc. Generally speaking you shouldn't send this token anywhere else as it contains sensitive user data.
The access_token is used to call other 'external' services (and by external I include other AWS services - these are often called over http). It provides service access authorisation for your user without having to include their personal details.
On the face of it this appears slightly confusing as you can actually use the id_token to access services in the same way as the access_token. However, good practise is to use the access_token in this circumstance and if backend services need user data, they should look it up themselves in Cognito.
EDIT: If you need to authenticate an api call based on claims in the identity token, there are circumstances when this is perfectly valid. But be aware of what details are in the identity token, and whether those claims are suitable to send to the particular API. If you don't need to use any claims from the id_token, use the access_token as this reduces the amount of potentially sensitive data you are sending.
The thing that wasn't obvious from documentation for me about the difference:
If you are using pretoken trigger function and want to add additional information to the claims with claimsToAddOrOverride , you need to use an id token because this information doesn't exist in the access token.
For ex:
event.response = {
claimsOverrideDetails: {
claimsToAddOrOverride: {
'userProfileID': id,
}
},
}
I've expected it in the AppSync resolver with lambda function as source
Speaking about AWS User Pool tokens:
Identity token is used to authenticate users to your resource servers or server applications. For example, if you use Cognito as authorizer in AWS API Gateway you need to use Identity token to call API.
The purpose of the access token is to authorize API operations in the context of the user in the user pool. For example, you can use the access token to grant your user access to add, change, or delete user attributes.
The header for the access token has the same structure as the ID token. However, the key ID (kid) is different because different keys are used to sign ID tokens and access tokens.

Can I use Cognito Access Token to generate an ID Token?

Is it possible to use the Cognito Access Token to generate an ID Token? I couldn't find any documentation on this online.
I'm trying to get an ID Token with custom claims, but the existing solutions don't work for my situation (details here). As a workaround, I'm thinking of manually asking Cognito for an ID Token directly with the Access Token after the user logs in.
What I tried
calling Cognito's /oauth2/userinfo endpoint only returns the basic claims, not the custom claims I had added via the pre token generation lambda trigger.
Adding custom claims/attributes to the access token. Seems like that's not supported.
Idea I haven't explored: use Amplify and somehow get ID Token through there?
You can use your access token to call the getUser method on the Cognito API:
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_GetUser.html
That will provide the user attributes:
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html
This provides the same data as you get on the ID token.
No.
If you need attributes inside an ID token, excluding open id claims such as exp, iss, aud, then maybe it's possible.
But if you need ID token (compliant with OIDC standard claims), then it is only issued by cognito upon specific cognito events.
The purpose of the ID token is to identify the user. ID token is often sent along the Authorisation header of a request to the backend server to be validated as a security measure. Knowing the purpose of the ID token, it will not be strange to understand why there are only specific ways to obtain the ID token.

Deleting cognito user & identity has no affect on user access

I am trying to use AWS Cognito user pools with Cognito federation as auth for my APIs on api-gateway. I got the authentication & authorization part (using roles) to work, but now stuck on how to revoke access. After login & getting the federated identity, I deleted the identity from identity browser (console) & deleted the user from cognito user pool. But that does not invalidate access using the earlier generated tokens, till they expire (which is a minimum of 1 hour).
I also tried setting ServerSideTokenCheck to true, but that doesn't work either. The only way to "revoke" access seems to be this. But this does not work for us as our use case assigns roles to a group. I cannot have groups of users lose access to revoke/deny access to one user.
Is there anything I have missed to get this done? I cannot fathom an auth service which does not give me easy way to revoke access to user.
This is a common case with stateless JWT tokens issued with Cognito for authentication.
Once a user got hold of a token which valid for 1 hour, the token itself acts as the proof for authentication. The token is signed and issued by AWS and for validation it only requires to do a signature verification using a publickey.
The approach you can handle this is at the authorization layer in your application where you can check either the user is active/deactive in your database after the user successfully authenticates. You can further delete the user from Cognito where he is not able to login back again.
I see what you are saying and as the other answer explained when the token is issued, the user can use the token until its expiry date. A solution to your problem can be handled two ways:
Cognito way: For this, you make two calls to Cognito, first if the user is enabled, second if so, authenticate its token.
DB way: You have a DB, which act as a "black list" holder, so when you want to disbale the user, the app, adds the username of the user to the DB. Therefore, when the user wants to authenticate, you first check with the DB (if the user is enabled), then check its cookie for authentication/authorization.
Note: If your user base is small, you could go the Cognito way, however there is a limit to Cognito calls, if you have a large user base; you should consider the second approach.

Retrieve user profile in Cognito Federated Identities

I'm currently exploring the AWS stack and am therefore building a simple web app. I plan on using:
S3 to host the static contents
DynamoDB to store user data
Lambda + API Gateway for backend logic
Cognito Federated Identities to authenticate users
I currently have a small tracer bullet application working that allows the user to authenticate with Google (through Cognito) and retrieve some data through a Lambda from DynamoDB. Now I want to extend it.
The next thing I want to do (and am failing to achieve) is to actually store the user name and e-mail of the authenticated user. Storing it shouldn't be a big problem, but retrieving it is. I know I initially got the data from Google because when I inspect the ID token (on JWT.io) I got from Google, I can clearly see my e-mail and name. This is the token I sent to AWS Cognito in exchange for a Cognito token.
I was expecting to be able to access this data again in my Lambda function, but I fail to figure out how actually. I understand Cognito performs a one way hash on the retrieved ID token, but I would expect some options to actually retrieve relevant user data from the token. After all, by authentication through Google (or any other IdP) a user already consented to sharing some personal data.
I feel I fail to see something obvious. Is there any feature in AWS that solves this? Is there a moment (not on the client side) where I can inspect the ID token and do some magic with it? Or should I solve this in some different way?
If the latter is the case: what would be the preferred way? I don't want users to tell me their personal data, because then I would also need some way to validate it.

How to link developer authenticated user across devices in Cognito

I'm just trying to get a handle over this framework and I want to confirm that my approach is correct.
I can authenticate my own user using the method: getOpenIdTokenForDeveloperIdentity and supplying an IdentityPoolId and a Logins key-pair with my Developer provider name and a token which I provide.
Now, from what I understand, when the user logs into a second device, in order for Cognito to understand that this is the same user, I have to provide it with an IdentityId. However, I'm not sure of the best way to get the IdentityId programmatically so that it will match up with the initial login.
The only technique I can think of is to store the IdentityId in my own DB and provide my own method for retrieving it. Is this the best way? Or should I be working with this framework differently?
I'm still a beginner to AWS in general and I'm just trying to understand the best practices for this framework.
BTW, I'm implementing the Android SDK and the PHP SDK for my backend.
When you use getOpenIdTokenForDeveloperIdentity, it returns the identity id associated with the user identifier you provided. So if the user identifier you use is the users' username, when you call getOpenIdTokenForDeveloperIdentity with that same username from the second device, it will return the associated identity id. There is no need to store the identity id unless you want to, it is provided to you each time you call getOpenIdTokenForDeveloperIdentity.
This blog post may be of further help:
http://mobile.awsblog.com/post/Tx2FL1QAPDE0UAH/Understanding-Amazon-Cognito-Authentication-Part-2-Developer-Authenticated-Ident
When you use Cognito, your user first authenticates with an Identity Provider (such as facebook, google or other Oauth provider), and the token you get back from it is sent to Cognito and is the key to tying your users information together across logins on other devices.
You don't need to store this information in a database, unless you are writing you own custom identity provider and not using one of the public ones available.