In AppSync, when you use Cognito User Pools as your auth setting your identity you get
identity:
{ sub: 'bcb5cd53-315a-40df-a41b-1db02a4c1bd9',
issuer: 'https://cognito-idp.us-west-2.amazonaws.com/us-west-2_oicu812',
username: 'skillet',
claims:
{ sub: 'bcb5cd53-315a-40df-a41b-1db02a4c1bd9',
aud: '7re1oap5fhm3ngpje9r81vgpoe',
email_verified: true,
event_id: 'bb65ba5d-4689-11e8-bee7-2d0da8da81ab',
token_use: 'id',
auth_time: 1524441800,
iss: 'https://cognito-idp.us-west-2.amazonaws.com/us-west-2_oicu812',
'cognito:username': 'skillet',
exp: 1524459387,
iat: 1524455787,
email: 'myemail@nope.com' },
sourceIp: [ '11.222.33.200' ],
defaultAuthStrategy: 'ALLOW',
groups: null }
However when you use AWS_IAM auth you get
identity:
{ accountId: '12121212121', //<--- my amazon account ID
cognitoIdentityPoolId: 'us-west-2:39b1f3e4-330e-40f6-b738-266682302b59',
cognitoIdentityId: 'us-west-2:a458498b-b1ac-46c1-9c5e-bf932bad0d95',
sourceIp: [ '33.222.11.200' ],
username: 'AROAJGBZT5A433EVW6O3Q:CognitoIdentityCredentials',
userArn: 'arn:aws:sts::454227793445:assumed-role/MEMORYCARDS-CognitoAuthorizedRole-dev/CognitoIdentityCredentials',
cognitoIdentityAuthType: 'authenticated',
cognitoIdentityAuthProvider: '"cognito-idp.us-west-2.amazonaws.com/us-west-2_HighBob","cognito-idp.us-west-2.amazonaws.com/us-west-2_HighBob:CognitoSignIn:1a072f08-5c61-4c89-807e-417d22702eb7"' }
The Docs says that this is expected, https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html .
However, if you use AWS_IAM
connected to Cognito (which is required to have unauthenticated access), how are you supposed to get at the User's username, email, sub, etc? I need access to the user's claims when using AWS_IAM
type Auth.
Here is bad answer that works. I notice that
cognitoIdentityAuthProvider: '"cognito-idp.us-west-2.amazonaws.com/us-west-2_HighBob","cognito-idp.us-west-2.amazonaws.com/us-west-2_HighBob:CognitoSignIn:1a072f08-5c61-4c89-807e-417d22702eb7"
contains the Cognito user's sub (the big after CognitoSignIn). You can extract that with a regex and use the aws-sdk to get the user's info from cognito user pool.}
It's a bad answer because you are pinging the User Pool database instead of just decoding a JWT.
If you are using AWS Amplify, what I did to get around this was to set a custom header
username
as explained here, like so:then in my resolver I would have access to the header with:
As explained by the AppSync's docs here in the section Access Request Headers
Here is my answer. There was a bug in the appSync client library that would overwrite all custom headers. That has since been fixed. Now you can pass down custom headers that will make it all the way to you resolvers, which I pass to my lambda functions (again, note I am using lambda datasourcres and not using dynamoDB).
So I attach my logged in JWT on the client side and, server side in my lambda function, I decode it. You need the public key created by cognito to validate the JWT. (YOU DO NOT NEED A SECRET KEY.) There is a "well known key" url associated with every user pool which I ping the first time my lambda is spun up but, just like my mongoDB connection, it is persisted between lambda calls (at least for a while.)
Here is lambda resolver...
This is WAY better than my other "bad" answer because you are not always querying a DB to get info that you already have on the client side. About 3x faster in my experience.
For making User's username, email, sub etc. accessible through AppSync API, there's an answer for that: https://stackoverflow.com/a/42405528/1207523
To sum it up, you want to send User Pools ID token to your API (e.g. AppSync or API Gateway). Your API request is IAM authenticated. Then you validate the ID token in a Lambda function and now you have your validated IAM user and User Pools data together.
You want to use the IAM's
identity.cognitoIdentityId
as primary key for you User table. Add the data included in ID token (username, email, etc.) as attributes.This way you can make user's claims available through you API. Now, for example, you can set
$ctx.identity.cognitoIdentityId
as the owner of an item. Then maybe other users can see the name of the owner via GraphQL resolvers.If you need to access the user's claims in your resolver I'm afraid that doesn't seems to be possible at the moment. I have made a question about this as it would be very helpful for authorization: Group authorization in AppSync using IAM authentication
In this case, instead of using a resolver you could use Lambda as a data source and retrieve the user's claims from the above-mentioned User table.
It's all a bit difficult at the moment :)