Do cognito custom attributes added by your pre-token-generation lambda show up in GetUser?

0

I am adding a bunch of claims to my ID token using a cognito pre-token-generation trigger. It works great as far as getting those attributes into the JWT.

Later, when someone calls one of my lambdas (through API Gateway) they use an AccessToken. The lambdas that care then call cognito GetUser. I got pretty far down the development path before I realized: the claims I added in my preauth trigger don't show up in the response to GetUser. The custom attributes are named "custom:ro" and "custom:rw" so I prefixed them correctly. But they don't show up.

I guess I had assumed that when you pass GetUser an access token, it would return to you information from the corresponding ID token. But that does not seem to be the case, it seems like it just returns info from the user pool. My synthetic UserAttributes of course aren't in the user pool, the whole point of my preauth lambda is to add them. The trouble is that API Gateway is just passing the Authentication header on, which is Bearer + access token, not ID token.

Do I have this right? Is GetUser ignoring the custom claims added by my pre-token-generation? And if so, how could the lambda get to these claims?

Update: I think I've figured this out. Since you're only using the access token in the standard jwt api gateway authorizer, you don't have access to the claims you inserted into the ID token. You shouldn't use the ID token as the access token for a few reasons, and doing so doesn't work with the standard JWT authorizer anyway so that would mean a lambda authorizer. That seems like a bad plan so I'll avoid it.

This gives me a few options:

  • I can use the access token in my API lambdas to look up my extra data on every request. This is basically doing what my pre-token-generation lambda does, but at every request
  • I could have my front end code send the access-token in the Authorization http header, and send the ID token in some other header. Doing that would mean that I would have to verify the signature on the ID token manually, upon every request.

I'm not quite sure what to do here. Any direction greatly increases the requests my api lambdas have to make, for instance two dynamodb gets instead of just one. Caching in the lambdas doesn't work for very long (the lifetime of the lambda, which you can't control).

profile picture
wz2b
asked a year ago2042 views
2 Answers
2

When you call getUser and pass in an access token, Cognito returns the attributes defined in the user pool schema. It does not interpret the claims in the access token. Per the OpenID definition, an Access token should be used only for access authorised resources.

https://aws.amazon.com/blogs/mobile/how-to-use-cognito-pre-token-generators-to-customize-claims-in-id-tokens/

This is neatly summed up in the following blog.

https://auth0.com/blog/id-token-access-token-what-is-the-difference/#What-Is-an-Access-Token-NOT-Suitable-For

On the access token side, it was conceived to demonstrate that you are authorized to access a resource, e.g., to call an API. Your client application should use it only for this reason. In other words, the access token should not be inspected by the client application. It is intended for the resource server, and your client application should treat access tokens as opaque strings, that is, strings with no specific meaning. Even if you know the access token format, you shouldn’t try to interpret its content in your client application.

For managing permissions of users in Cognito, consider adding groups to your user pool. https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-user-groups.html

You can use groups to create a collection of users in a user pool, which is often done to set the permissions for those users. For example, you can create separate groups for users who are readers, contributors, and editors of your website and app.

Let me now how you go or if I have missed the meaning of your question and I'll be happy to help further.

profile pictureAWS
simon
answered a year ago
  • You did understand my meaning. I would like to use groups but the problem is I think I would need a LOT of them, because my permissions are really more like hierarchical paths in a resource tree. There's a ro tree and a rw tree, if you have the 'permission' that implies you have it from that spot in the tree down to the bottom. So in DynamoDB, it's a Set<string>

  • Got it. Agree that it would become cumbersome managing using groups. This is one of the main customer requirements we're aiming to solve with Amazon Verified Permissions. https://aws.amazon.com/verified-permissions/

    The service is in Preview and you can request access through the product page.

  • Right. Really, the main thing I want is some way to cache this. An ID token is kind of convenient because the client "caches" it. It's like you tell the client "Hold this for me, but don't change it, then show it to me later." What I'm really trying to do is avoid my clients having to incur a database or cognito lookup per request.

1

While @simon answer is the real reason, there is an alternative. You can request to refresh the Access Token which will provide you with a new ID token that will be issued after passing through the Pre-Token Generation Lambda:

Sample request

POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token >
                           Content-Type='application/x-www-form-urlencoded'&
                           Authorization=Basic ZGpjOTh1M2ppZWRtaTI4M2V1OTI4OmFiY2RlZjAxMjM0NTY3ODkw
                           
                           grant_type=refresh_token&
                           client_id=1example23456789&
                           refresh_token=eyJj3example

Sample response

HTTP/1.1 200 OK
                           Content-Type: application/json
                           
                           {
                           "access_token":"eyJra1example", 
                           "id_token":"eyJra2example",
                           "token_type":"Bearer", 
                           "expires_in":3600
                                 }
AWS
answered a year ago
  • Ahh so in this case I'd have to pass the Refresh token (in addition to the Access token) into my API calls. If I understand you, you're saying that I could just request a refresh, get an ID token back, and then you won't have to validate any tokens yourself because Cognito won't issue a new set of tokens unless Refresh was valid.

    That makes sense but I worry that I'll be requesting a refresh for every API call, that won't wig cognito out?

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions