Amplify-js: Access token passed to appsync resolver causes missing email claim

Created on 21 Jan 2020  路  6Comments  路  Source: aws-amplify/amplify-js

This is half bug, half feature request, but I have decided that it fits better as a "bug" due to reasons listed below.

Describe the bug
The issue is described here, but I will summarize it below.

When using Appsync with a cognito user pool with email enabled, $ctx.identity.claims.email is missing in the resolver for a mutation if that mutation is called using the amplify-js library. The issue does NOT exist when called using the query editor in Appsync itself.

This causes problems when using a cognito user pool where users sign up by email address rather than specifying a custom username. Since the email address is the human-readable identifying factor in an account, it is desired that it be stored on the profile level. However, in this use case, the $ctx.identity.username field is identical to the $ctx.identity.sub field (the account's UUID), so to obtain a user's email address without obtaining the entire profile, it must be passed via claims.

To Reproduce
Steps to reproduce the behavior:

  1. Signin using cognito user pools via amplify-js
  2. Call the generated graphql mutation function
  3. In the resolver, check if $context.identity.claims.email is null (using $util.isNullOrEmpty())
  4. Find that $context.identity.claims.email is null because is does not exist

Expected behavior
$context.identity.claims.email should be populated with the cognito user's email address

Cause of issue
The issue is caused by the passing of the Access Token as authorization, while as claims are supposed to be obtained from the ID Token. See here (pointed out by cy6581 in the above stack overflow thread).

Using the Access token for claims is not in line with the cognito user pool documentation, which is why I classify this as a "bug". See here:

The ID Token contains claims about the identity of the authenticated user such as name, email, and phone_number.
The Access Token grants access to authorized resources.

API AppSync question

All 6 comments

I had a similar issue with the mock API: the mock API passes the id token but the real API passes the access token. I argued the opposite: both should use the access token by default.
https://github.com/aws-amplify/amplify-cli/issues/3062
Either way, you're right that all of the methods (mock API, Appsync console, real API) should be consistent in their use of either the id token or the access token.

Hi @atlowell-smpl

What @dantasfiles points out is correct, the console uses the ID token and Amplify uses the acces token.

With code like this you can make Amplify use the ID token too:

const Amplify = require('aws-amplify').default;

Amplify.configure({
    API: {
        aws_appsync_graphqlEndpoint: 'https://xxxxxxxxxxxxxxxxxxxxxxxxxx.appsync-api.us-east-1.amazonaws.com/graphql',
        aws_appsync_region: 'us-east-1',
        aws_appsync_authenticationType: 'NONE',
        graphql_headers: async () => ({
            'Authorization': (await Auth.currentSession()).getIdToken().getJwtToken()
        })
    }
});

Amplify.API.graphql({
    query: 'query { someType { someField } }',
}).then(console.log, console.warn);

I hope this helps.

@manueliglesias that is actually what we have been doing to get this to work, but it seems more like a workaround than a fix. Considering appsync has support for claims, and cognito claims expect the id token, I think the default token passed to appsync by amplify should be the id token. But as @dantasfiles also mentioned, there should at least be consistent use of tokens across services.

@manueliglesias

Worked for us :)

+1 for at least making this consistent. Wasted many hours diagnosing why same exact user query would work in app sync console but fail as unauthorized in actual client. The reason is console uses id token and Amplify client uses access token, which does NOT include custom attributes like the id token does. Above fix resolved for me (thanks!), but feels like a hack. If it is supposed to be access token for better security, then the app sync console should also use it, and custom attributes should be included in the access token so that we can write authorization rules against custom attributes.

+1 for always using id token (or at least to support both)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rygo6 picture rygo6  路  3Comments

callmekatootie picture callmekatootie  路  3Comments

cgarvis picture cgarvis  路  3Comments

karlmosenbacher picture karlmosenbacher  路  3Comments

guanzo picture guanzo  路  3Comments