Open rscmendes opened 5 years ago
Thanks all. We're working internally to figure out the best way to tackle this. This is our top feature request in this repo so it's top of mind. Please feel free to share your use cases here and +1 the issue.
I just can't express how important it is to be able to add customized information to the access tokens in the microservice paradigm that more and more companies try to be in these days. Using the ID token for microservice authentication is out of question since it contains PII information and it is also forbidden by the OIDC spec, and yet customizing the ID token is given a lot of attention by the Cognito team. The access_token customization needs to be super powerful in the microservice context. In our case, we have companies as customers, those companies have their own customers and we need to include tenancy and role information in this token ("what is the company ID/tenant ID for the user that requested this access token ? ").
For those that need a dirty hack to encode some customized information in the access_token, until a solution is available:
You can programmatically add a user to a group, and you can programatically create groups, so you can create group names containing some encoded (non-sensitive) information that you would like to be present in the access_token. Then add users to these groups, the list of groups will be included in the access_token and you can read this per-user customized information in your services using some simple custom middleware. Of course, there is a limit of 10000 groups per user pool...but it may work for some until a solution is available :)
@cstavaru
We have similar requirements and I share your view on the "disproportionate attention" the id_token
gets compared to the access_token
in my comment above https://github.com/aws-amplify/aws-sdk-android/issues/684#issuecomment-642271673.
Thank your for sharing your approach for a workaround.
I thought I'd share mine too, that I've posted in #cognito in og-aws
slack workspace.
About our use case:
My current use case is quite simple actually. I want to move OAuth2 client apps from our current provider to Aws Cognito. It's mostly straightforward as currently it's only about m2m clients (client_credentials), but there are some challenges. One of them is that currently there is no way to enrich the access_token (lambda trigger only available for the id_token , a bit of context at https://github.com/aws-amplify/aws-sdk-android/issues/684#issuecomment-642271673) although I can achieve that with some creative "abuse" of custom scopes (not ideal, but it's possible). The other one is that when moving the apps over to Cognito I would like to keep the client_id and client_secret as to not force the consumers to get new credentials. I don't think this is possible though.
I contacted AWS support to which they acknowledged the Cognito limitations I raised in the context of our requirements - no lambda trigger for the access_token
or the ability to add some custom data to user pool clients.
My solution (hopefully temporary if the Cognito team ends up implementing some of the mentioned features) was to use a DynamoDB table as the canonical store for user pool client data and signing our own access_token.
When creating a user pool client, it gets added to this DynamoDB table. When a grant is executed (client_credentials in this case), our backend finds the client_id in the dynamodb table and makes the call to the oauth2 token endpoint on the Cognito domain. We take the returned access_token, verify it and use part of it to construct our own access_token (providing us the flexibility to be in charge of it structure). We use a KMS signing key to do the signing.
It's a bit more custom than we would like but it does the job, and allows us to move our M2M OAuth clients to Cognito while dropping the costs from our previous provider by an order of magnitude.
Also by using this approach we can move our existing clients while keeping their credentials, which is a big win, not having to bother customers to update their integrations.
Not too bad for about a weeks worth of work.
It works pretty nicely. I was able to switch to Aws Cognito with no impact on our API consumers. After all, it's an implementation detail right? :wink:
Hey everyone, here is our use case as well. We have some APIs that needs role base access for our web clients, however, we want to also expose these APIs with M2M authentication (client_credentials) for our programmatic clients. So I believe using custom scopes will help us a lot to overcome with our use case. At the end we either need to modify access_token with a kind of a lambda trigger before authentication step or making resource server to inject custom scopes based on some attributes. Any ideas how to support this use case until Cognito team provides a way to achieve this? Thanks.
In our use case we provide services to retailers. We provide them with a web app where we would need to use custom scopes to handle permissions for API request.
Heya @warrify (and anyone else with this need)! Just a quick clarification: have you looked into using Lambda Authorizers to provide this functionality instead? It's true that the Cognito User Pools authorizer requires Custom Scopes which only work with OAuth (Hosted UI), but you should be able to implement your own authorization logic using Lambda Authorizers.
@jpignata we did already try that but aren't satisfied with the response times we got (even with provisioned concurrency and credentials caching). Since we are right at the point of sale, time is somewhat of a constraint.
Also I am a bit weary of implementing my own authentication, which is why we chose cognito in the first place.
Anyway in our case we had a chat with an AWS Solution Architect and someone from AWS specialized in this and for our use case they said that relying on API Keys alone (which isn't generally recommended in the docs) is fine
Thanks. Do you have any recollection of the performance you saw? It seems like using Lambda Authorizers is our only current workaround to this limitation at present.
Hi @jpignata we implemented our own Lambda custom authorizer to support both IdToken and AccessToken along with custom scopes, however, when generating Policy Statements we have to give *
to incoming authorized requests and we can't cache these. For example;
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": "arn:aws:execute-api:eu-central-1:111111111111:2222222222/live/GET/*"
}
]
}
As you know, if we enable caching then other requests coming from same entity will get blocked. Additionally, we have 50+ APIs so returning a list of ARNs doesn't look like an optimal solution since Statement has limitation on number of resources if I am not wrong. Do you have an idea about the workaround to enable caching? A similar issue is mentioned in this topic as well https://www.alexdebrie.com/posts/lambda-custom-authorizers/#choosing-a-cache-key.
Thanks
@flexelem Hmm, I don't. I'll circulate this internally -- thanks so much for the detail.
To share a use case...
We may use Cognito for OAuth flows in the future, but for right now we are really just leveraging it as an outsourced identity provider. Meaning, we host a login UI ourselves and use the SRP Cognito flow to authenticate. While we could certainly just use Cognito as an authenticator, we'd also like to keep authorization in there as well - especially considering that one of the suggested uses of user groups is to control permissions.
Ideally, we'd like to simply look at the groups the user is a part of, and list their corresponding scopes in an access token to the user's client. The most straightforward way of doing this seems to be a single lambda trigger to enrich both the access and id token.
In the meantime - since we don't actually need to uphold OpenID Connect semantics for other clients - we've just abused the id token into being an access token.
I'm very interested in having a pre-token-generation
lambda for access tokens, rather than id tokens, as others in this thread have suggested. Eagerly awaiting any progress on this feature.
@jpignata, any update from the Cognito team regarding this essential feature?
Hi @jpignata is there some progress to share? Would be great.
Please do provide update about this @jpignata ; would be quite helpful.
Any updates on native support for this?
PS. There is a workaround for this posted here: https://github.com/aws-amplify/amplify-js/issues/3732#issuecomment-780466923 but this method is more complicated and involves a lot more configuration of the http event syntax.
I am currently facing the same issue where I have to assign custom scope to users who signing in via InitiateAuthAsync
flow. Any update to this issue would be much appreciate it.
A lambda function would be really helpful to add/modify scope on the access token.
I have a workaround for those who are using the HostedUI with Cognito and Amplify hosted app:
In the Allowed OAuth Flows for now I have checked Implicit grant.
If you have the SignupURL provided, like this:
https://&scope=email+profile+aws.cognito.signin.user.admin
&redirect_uri=https://
but it sure is not the best way, because with Implicit grant Allowed OAuth Flows there are more chances that a JWT will be compromised.
any updates on this?
I highly doubt, given the amount of attention this issue is getting in all amplify sdks, that anyone in the entire world is using cognito hosted UI except maybe AWS. To say this is a much-needed feature would be an understatement, this issue is probably the primary (perhaps only) reason cognito fails to deliver.
@jpignata is this even on a roadmap? Using cognito as an identity provider has become painful with issues like these. For most people, cognito hosted UI is not an option, and without features like these, we're forced to implement our own solutions which makes cognito a glorified user store.
You know what's sad. I didn't do enough research, I don't even know what to research before I started coding. I've already wasted so much time just to run into this roadblock.
Now I'm just facing sunk cost fallacy.
Know what's even sadder? I worked at Auth0 and decided to go with Cognito for my startup because of its supposed frictionless development with AppSync.
You know what's sad. I didn't do enough research, I don't even know what to research before I started coding. I've already wasted so much time just to run into this roadblock.
Now I'm just facing sunk cost fallacy.
Know what's even sadder? I worked at Auth0 and decided to go with Cognito for my startup because of its supposed frictionless development with AppSync.
There is a work around you can use in order to get this working. You will have to call same api they call from hosted UI and pass their Token that is set to your browser in the cookies I believe (Sorry I dont remember the name of the cookies, it is on my work computer, but it starts with X I believe). With this youll be able to sent your scopes in the url of the request.
Thanks, I have both the id_token
and the access_token
. So the workaround for me right now is to send the id_token instead since that contains the claims.
However:
id_tokens are meant for the client and access_token for the API. See https://auth0.com/blog/id-token-access-token-what-is-the-difference/
I somehow need to override the default access_token with my claims from the source. Worst case I'm going to have to implement a lambda auth and use that to pull in my id_token with the claims (which is storing authz info such as tenant and role).
So while it's not an amplify issue but a cognito issue, the amplify team is taking the heat for this because it's mostly what we're interacting with, by the same company.
Thanks, I have both the
id_token
and theaccess_token
. So the workaround for me right now is to send the id_token instead since that contains the claims.However:
id_tokens are meant for the client and access_token for the API. See https://auth0.com/blog/id-token-access-token-what-is-the-difference/
I somehow need to override the default access_token with my claims from the source. So while it's not an amplify issue but a cognito issue, the amplify team is taking the heat for this because its mostly what we're interacting with, by the same company.
You should not use id token in place of access token, it is bad for security. Also, id token will have missing claims. I believe it won't have username claim as well as scopes I believe
@kkdeveloper7 you can add claims via the PreToken trigger for id tokens. I outlined a solution/workaround in this issue
Can you elaborate regarding using of id tokens is bad from a security perspective?
@kkdeveloper7 you can add claims via the PreToken trigger for id tokens. I outlined a solution/workaround in this issue
Can you elaborate regarding using of id tokens is bad from a security perspective?
Generally speaking you can even sent a refresh token in a header that you can later take retrieve access token from and access your protected resource, but it is not recommended to do so because of the security concerns that if someone get a hold of your long living refresh token and will be able to issue them new access tokens.
Id token was created to be able to quickly gain current user information. This token dose not have to be secure and can be accessed via client to parse its contents in order to get users information. If you will store secure information in your Id token this mean that the client can access it and read secure claims that mean to be for access token only, such as scope
claim (just an example there could be other scopes that you might use).
The point I am trying to make is that, yes passing id token is not as bad as passing refresh token, but it is not recommended since the use for this token is mean for other purposes. Its like trying to eat soup with tea spoon, yes you can get it done but there are better tools for that.
There are also scopes that you cant add or modify in lambda one of the is cognito:username
. I think cognito:username
is used in id token and username
is used in access token. There are probably more, sorry I dont remember from top of my head but I ran into same issue and was cough of guard with certain limitations.
After 3 days trying to find out why my Amplify token does not work with my proxy API, I figured out the scope issue and landed here.
Quite frustrated as I don't want to use hostet UI, I don't know how to continue. Shame on AWS.
It’s not ideal, but we ended up implementing our own endpoint which takes the cognito access token and provides a custom access token. Refresh and Id tokens work as usual. This allowed us to give custom scopes while still using Cognito as the identity provider.
Sent from my iPhone
On Dec 7, 2021, at 12:28 AM, Andreas Hernitscheck @.***> wrote:
CAUTION: This email originated from outside your organization. Exercise caution when opening attachments or clicking links, especially from unknown senders.
After 3 days trying to find out why my Amplify token does not work with my proxy API, I figured out the scope issue and landed here.
Quite frustrated as I don't want to use hostet UI, I don't know how to continue. Shame on AWS.
— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/aws-amplify/aws-sdk-android/issues/684#issuecomment-987582166, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AOPHKY4NGKZAG6LK4MTMZ3TUPWLQHANCNFSM4GT67PSQ. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
Found this: https://aws.amazon.com/blogs/security/use-amazon-cognito-to-add-claims-to-an-identity-token-for-fine-grained-authorization/ Is pretty new.
That is an article about adding claims to the id_token
. That functionality has been available for quite some time. The missing functionality, and the context of this issue, is adding claims to the access_token
. :)
+1 I am having this issue. How is Amazon using this to identify users? Are they using an access token or the id token?
I run into this issue even using the hosted ui. I have no way around it that I know of. :/
Why is there still no news on this? It's incredibly frustrating to see people including me paying money for Cognito and Amplify, yet this critical issue, which affects all Amplify SDKs, continues to be overlooked!
Hello everyone, this is currently a limitation from the Amazon Cognito service, and we are working closely with them to resolve this. We will provide updates on this issue when we have more to share.
Looking forward for a resolution for this issue.
Since we are working with the Cognito team to identity the use cases for how developers would use this, can you please help us with providing us how you would set and also request these custom scopes? We want to make sure the mechanism we expose this in makes sense.
Here is my use-case:
I have two Angular web apps integrated with Module Federation. In the main application, I handle authentication using Amplify/Cognito APIs. The second app is configured to use OpenID with Cognito. Now, what I want to do is to reuse the token generated from sign-in calls in the main app to make API calls from the second app (Module Federated). When the native Amplify Auth is used, the generated token lacks the 'scope: openId,' and as a result, it can't be used to make requests to the second app. The solution is to eliminate the native Amplify Auth component and use Cognito APIs with OpenID (which forces the use of the native and somewhat unattractive Cognito authentication page - Hosted UI) to obtain a scoped token.
From my investigation, from the Cognito side, you can't have a programmatically generated scoped token, besides then going throw SSO Cognito(Hosted UI) login page.
Let me know if you need more details.
As on how to query those scopes: I think it's not necessary to query them because they should be returned by default if the SSO is configured, and they are returned but only throw Hosted UI:
This is the override of Amplify Auth, configured with SSO.
When going to the Hosted UI login - the scoped token is returned. When calling directly the APIs for that native Auth component, they are not.
Since we are working with the Cognito team to identity the use cases for how developers would use this, can you please help us with providing us how you would set and also request these custom scopes? We want to make sure the mechanism we expose this in makes sense.
Setting and requesting custom scopes is not the issue. This is possible with the current functionality:
scope
request param)What is missing and would add immense value and flexibility is allowing developers to take control over the structure of the access_token
. I make the case in https://github.com/aws-amplify/aws-sdk-android/issues/684#issuecomment-642271673 (June 2020):
It makes sense that there is a trigger to modify the
id_token
, given the support for custom/additional claims (https://openid.net/specs/openid-connect-core-1_0.html#AdditionalClaims). However it makes even more sense to have one for theaccess_token
sinceid_token
is arguably more strict in it's structure (there's a spec for it: https://openid.net/specs/openid-connect-core-1_0.html#IDToken) while an OAuth2access_token
has no specific format or structure as per the OAuth2 spec (https://tools.ietf.org/html/rfc6749#section-1.4, https://tools.ietf.org/html/rfc6750) effectively making it application specific.
In terms of supporting this, it would make sense to keep consistency with current Cognito functionality and simply provide a pre (or post) (access) token generation trigger similar to the one available for the id token (https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-token-generation.html).
Note that there are a significant number of claims in theid_token
that can't be modified in the existing trigger. I would advise that when the Cognito team considers adding the new trigger :pray: that the constraints on the modification of the claims in the access_token
be carefully thought out and likely very loose. As I refer to above, the id_token
has a spec, the access_token
doesn't.
See also https://github.com/aws-amplify/aws-sdk-android/issues/684#issuecomment-669413838 for some context about our use case and the workaround I've implemented to have full control over the structure of the access_token
.
I, of course, don't have the context the Cognito team possesses regarding the architecture, design and implementation of the Cognito service, however, I might be so bold to argue that the uses cases are of less importance and not really relevant in the consideration of what should be a core functionality: allowing developers to have full control over the access_token
that is used to access their APIs.
:bow:
Thank you @hackmajoris and @jsmpereira so much for the feedback! Exactly the type of insight we needed! We will get back to you when we make more progress with the help of the Cognito team!
@jsmpereira Perhaps I'm misunderstanding the guides, but the custom scopes seemed to be mapped to app clients only? This is fine for app clients but what about users in the pool? It would be nice to a have custom logic when it comes to issuing scopes regardless of the client type.
@AlexMayleRdn From the OP (https://github.com/aws-amplify/aws-sdk-android/issues/684#issue-406014075):
Describe the bug Impossible to get access tokens with custom scopes without using the hosted web ui. Authentication through the amplify drop-in UI for both Android and iOS -- used in the android-sdk-auth example -- or through cognito auth sdk always returns (the single scope) aws.cognito.signin.user.admin even if it is disabled on the app client settings. ... Expected behavior Access token should return custom scope(s), regardless of using the web ui.
The issue initially described seems to be a "limitation" with amplify and related SDKs, where unless you used the hosted ui, any custom scopes would not be present in the access token. At this point, 4 years passed I honestly don't know if that issue is addressed. It sparked however a more "generic" discussion about access token customisation.
Custom scopes are defined on a Resource Server (https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-define-resource-servers.html). These scopes can then be enabled in app clients. When executing OAuth grants "in the context" of a user pool app client (https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html) you get an access_token
which includes the requested scopes, if enabled.
An app client is not a client type and it "links" your application to a pool of users. An app client can have different types: "Public client", "Confidential client" or "Other".
If you want to leverage Cognito to authorize your own API you can do so with Resource Servers and custom scopes, then you can enable the desired custom scopes on your app client. If you have no users to authenticate, you can execute a client_credentials
grant (specifying the app client credentials) and get an access_token
with the enabled (custom) scopes. if you have users to authenticate you can execute an authorization code
grant (also specifying app client credentials) and get an id_token
with OIDC claims (and some cognito specific claims) and an access_token
with the enabled (custom) scopes in the scope
claim.
I don’t think it currently works as you described @jsmpereira. In my tests the custom scopes are only present in the Access Token if you use the Hosted UI
@tobilg :bow: That is indeed the issue initially described, as I do mention in https://github.com/aws-amplify/aws-sdk-android/issues/684#issuecomment-1705729687:
The issue initially described seems to be a "limitation" with amplify and related SDKs, where unless you used the hosted ui, any custom scopes would not be present in the access token. At this point, 4 years passed I honestly don't know if that issue is addressed. It sparked however a more "generic" discussion about access token customisation.
This however seems to be by design. From the Cognito access token page (https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-access-token.html):
scope A list of OAuth 2.0 scopes that define what access the token provides. A token from the Token endpoint can contain any scopes that your app client supports. A token from Amazon Cognito API sign-in only contains the scope
aws.cognito.signin.user.admin
.
It does seem that something like Amplify's Auth.signIn
(https://github.com/aws-amplify/amplify-js/issues/1370#issuecomment-476372434) doesn't trigger an OAuth flow and hence won't be in context of resource servers and custom scopes. It could be nice if the Cognito team could share the rationale for this design decision. Maybe the Cognito API sign-in is only intended to provide an access_token to access Cognito APIs, like updating user information :shrug:.
I also mention in a previous comment https://github.com/aws-amplify/aws-sdk-android/issues/684#issuecomment-642271673:
It seems the use cases presented are mostly in the context of users and the hosted UI.
I believe however that the underlying issue is more general and not exclusive to the context of amplify. It boils down to allowing the access_token to be modified, for example via a trigger (see related issue https://github.com/aws-amplify/amplify-js/issues/4015).
Providing something like a pre-token-generation trigger (used to modify the id_token) for the access_token would address any issues related to what is/should/shouldn't be in the access_token. How the authentication is being done (hosted UI or API) should be irrelevant. What the developer decides to put on the access_token is application specific and should just be there.
I make the case on that comment that having a trigger for the access_token
(like the one that exists for the id_token
) is (arguably) core functionality that seems to arbitrarily be absent, that would address the reported issue while giving developers optimal flexibility and control over the access_token
used to authorize their APIs. But again, as I mention above, maybe the access tokens issued by cognito are not all intended to authorize our APIs :sweat_smile:
Sorry about the ramblings. I'm all over the place :bow:
I‘m aware of all these things. They have been mentioned years ago in other issues. Current discussion seems to revolve around https://github.com/aws-amplify/amplify-js/issues/3732#issuecomment-1702116346
CHRISTMAS CAME EARLY FRIENDS
Seems to have been fixed on Cognito User Pools: https://aws.amazon.com/about-aws/whats-new/2023/12/amazon-cognito-user-pools-customize-access-tokens/
Does this mean that api gateway will use access tokens instead of id tokens now?
https://github.com/aws-amplify/aws-sdk-android/issues/684#issuecomment-1861890646
Well... not exactly. You must turn on advanced security features to use this. This bumps per user price up 800%....
Surely we can get this without needing to opt into every other feature.
Describe the bug Impossible to get access tokens with custom scopes without using the hosted web ui. Authentication through the amplify drop-in UI for both Android and iOS -- used in the android-sdk-auth example -- or through cognito auth sdk always returns (the single scope) aws.cognito.signin.user.admin even if it is disabled on the app client settings.
To Reproduce Steps to reproduce the behavior: 1.Follow the android (or iOS)-sdk-auth example;
Which AWS service(s) are affected? AWS Cognito (in all SDKs) and AWS API Gateway
Expected behavior Access token should return custom scope(s), regardless of using the web ui.
Screenshots
Environment(please complete the following information):
Device Information (please complete the following information):
Additional context Our use case: We have native apps (both Android and iOS) trying to authenticate end-users in a user pool. Our API Gateway resources are scoped (none including aws.cognito.signin.user.admin scope). We want to use implicit grant as we don't want to distribute the application with the client secret in its package as that would be stored in plain text. We'd rather not use the hosted web ui for improved user experience, specially since everything we have is native. We do understand the implications of not using the web ui, as well as not using the authorization code flow. Thus, the solution would be to use the cognito auth sdk, which we believe that it doesn't support implicit grant.
We might be approaching this the wrong way, any guidance would also be highly appreciated.
Unsolved related issues throughout the different SDKs:
[Amplify JS] - Access Token does not have required scopes (Http - 400)
[Amplify JS] - How do I use amazon-cognito-identity-js to get scopes in the access_token?
[Amplify iOS] - Feature Request: Cognito "InitiaateAuth" request allowed custom "scopes" in AccessToken
[Amplify Android] - Feature Request: Cognito "InitiateAuth" request allowed custom "scopes" in AccessToken