Understanding ID Token vs. Access Token in AWS Amplify
Tags: aws, amplify, javascript, webdev
Published: 2023-04-11 11:00:00

> It has been pointed out to me that the suggested way to change the Access Token via Pre Token Generation does not work at the moment. The article has been changed accordingly.

In a recent StackOverflow [answer](https://stackoverflow.com/a/75885547/1967693), I addressed an issue related to the use of ID Token vs. Access Token in the Amplify JavaScript library. I think it's worth writing this up to provide further information and resources for people who might stumble upon this problem.

### ID Token vs. Access Token

The Amplify JavaScript library sends the JWT [Access Token](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-access-token.html) by default in GraphQL requests. However, the AWS console for AppSync, which powers Amplify's API module, actually sends the [ID Token](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-id-token.html) instead of the Access Token. This discrepancy can cause confusion among developers. The main reason to send the ID Token is that it contains user attribute information such as email, that we might need on the backend for authorization checks. 

To override the default behavior and [send the ID Token](https://github.com/aws-amplify/amplify-js/issues/4751#issuecomment-613717344) in the Authorization header for GraphQL requests, you can configure Amplify as follows:

```ts
Amplify.configure({
  API: {
    graphql_headers: async () => {
      const session = await Auth.currentSession();
      return {
        Authorization: session.getIdToken().getJwtToken(),
      };
    },
  },
});
```

However, there are security risks when using the ID Token in such a way.

### Add Claims to ID Token

We can modify the ID Token in a way that it contains the information actually need. AWS Cognito supports [Lambda triggers](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html) that execute code before or after certain events. In this case, the [Pre Token Generation Lambda Trigger](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-token-generation.html) allows us to hook into the token generation and add custom claims and groups to the ID Token, before it is being generated. 

Unfortunately, this solution does not currently work for the Access Token. This means that we expose the ID token and should be careful about this.

```ts
import type { PreTokenGenerationTriggerHandler } from 'aws-lambda';

export const handler: PreTokenGenerationTriggerHandler = async (event, context) => {
  const { email } = event.request.userAttributes;

  event.response = {
    claimsOverrideDetails: {
      claimsToAddOrOverride: {
        email: email,
      },
      // claimsToSuppress: ['some_attribute'],
    },
  };

  return event;
};
```

The event payload contains `request.userAttributes` object with properties such as first name, last name, email and so on. We have to modify the event and return it with the claims we would like to add, change or even suppress. In this case we add the email to `claimsToAddOrOverride` and return the event.

## Further Reading
Here are some links that might help you to dig deeper:

- [Pre Token Generation Lambda Trigger](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-token-generation.html)

- [Add Cognito Lambda Triggers to Amplify](https://docs.amplify.aws/cli/usage/lambda-triggers/#cognito-lambda-triggers)

- [Multi-tenant AWS Amplify](https://medium.com/@dantasfiles/multi-tenant-aws-amplify-cc3252c4def4)

- [Amplify GitHub Issue](https://github.com/aws-amplify/amplify-js/issues/4751
)
- [OpenID Standard Claims](https://openid.net/specs/openid-connect-core-1_0.html#Claims)

---

I hope you found this post helpful. If you have any questions or comments, feel free to leave them below. If you'd like to connect with me, you can find me on [LinkedIn](https://www.linkedin.com/in/christian-zirkel/) or [GitHub](https://github.com/zirkelc). Thanks for reading!