Is it safe to use ID tokens with Cognito authorizers?


A common narrative is that one should always use access tokens to call your APIs, while ID tokens are strictly for identifying users.

Some of it has come from this article by Auth0 [1], which makes a strong statement about using ID tokens:

However, things are usually more nuanced. In some cases, using ID tokens instead of access tokens is both acceptable and pragmatic. Cognito User Pools might be one of these cases.

Cost of using access tokens

The common practice amongst Cognito users is to use ID tokens.

Before January 2024, you couldn’t customize access tokens to include the OAuth scopes. So, using access tokens for authorization just wasn’t an option.

But now, Cognito lets you customize access tokens through the Pre-Token Generation trigger, like this [2]. With this, you can implement authorization in API Gateway using access tokens and OAuth scopes.

However, this requires Cognito’s advanced security features [3], which are charged much higher – starting at $0.050 per MAU and do not have a free tier. You must also pay the standard MAU cost for Cognito User Pools, which starts at $0.0055 per MAU and has a generous free tier of 50,000 MAU.

This significantly raises the cost of using Cognito User Pools. Here is how much it’d cost you per month with Advanced Security Features (using access tokens) vs. without (using ID tokens).

This might be fine for B2B use cases where you tend to have few high-value users. But it’s practically a death sentence for many B2C businesses, many of whom have thousands of free users.

“Why not use something else instead?”

For this many MAUs, you’d pay even more with vendors such as Auth0 and Okta. Most of whom require you to sign an enterprise contract before you can reach this scale.

Cognito’s greatest strengths are cost efficiency and its integration with other AWS services, such as API Gateway and AppSync. If access tokens are significantly more costly, one must ask,

“Is it worth it?”

Are access tokens more secure? If so, are they THAT much more secure and worth the extra cost?

ID tokens vs. Access tokens

Whenever I show an example of using Cognito with ID tokens, someone would tell me, “You should use access tokens instead!”. But, I have yet to hear a compelling argument for why ID tokens are less secure.

Let’s quickly debunk the common arguments.

“ID tokens are not designed for authorization”

Yes, access tokens were intended for APIs and ID tokens for authentication purposes. However, this division is not always necessary or practical.

After all, there is more than one way to implement authorization.

You can implement the authorization logic in the identity provider and embed the authorization decision in access tokens (in the form of OAuth scopes).

However, you can also implement the authorization logic directly in the API. In my last post [4], I demonstrated how you can do this with a Lambda authorizer and Cognito groups. We will also explore other ways to implement authorization with API Gateway in the coming weeks.

It’s two routes to the same result – being able to control who can do what in your system.

“ID tokens have more information”

This is true. ID tokens contain information about the user, such as their name and email.

But what can attackers do with this information if they managed to steal your ID tokens? Nothing. Most likely.

As an attacker, I have easier ways to acquire names and emails than to steal ID tokens from a system.

“ID tokens give you access to the API”

So does access tokens.

“Access token can only be created by a trusted source”

So are ID tokens.

“Access tokens have limited lifetime”

So can ID tokens. You can configure the validity period for both access and ID tokens in Cognito (and with other vendors). It’s a matter of making sensible architectural decisions.

“You can bind access tokens to specific senders to avoid abuse”

Yes, the Auth0 article mentioned this.

The linked article [5] (which is a good read, btw!) discusses two techniques:

  • Mutual TLS authentication (MTLS)
  • Demonstrating Proof-of-Possession (DPoP)

for binding a token to a specific sender.

However, nothing about these techniques is specific to access tokens. They will work equally well for ID tokens.

Summary

Until someone can prove otherwise, I believe it’s perfectly safe to use ID tokens with Cognito authorizers.

ID tokens are not inherently less secure than access tokens. Furthermore, all the techniques that make access tokens more secure also apply to ID tokens.

So, there are no security downsides to using ID tokens with Cognito.

On the other hand, there are significant costs to using access tokens.

I’m not saying that you shouldn’t use access tokens! In fact, I will show you how to use access tokens to implement authorization in API Gateway in the next post.

But you should know the trade-offs and not blindly pick a more costly approach based on hearsay.

Links

[1] “ID Token and Access Token: What’s the Difference?” by Auth0

[2] How to customize access tokens in Amazon Cognito user pools

[3] Cognito User Pool advanced security features

[4] Fine-grained access control in API Gateway with Cognito groups & Lambda authorizer

[5] Identity, Unlocked… Explained | Episode 1

Master Serverless

Join 11K readers and level up you AWS game with just 5 mins a week. Every Monday, I share practical tips, tutorials and best practices for building serverless architectures on AWS.

Read more from Master Serverless

Software systems are getting bigger and more complex. And we are constantly looking for ways to test code in production without risking user experience. Canary deployments is a popular mechanism for rolling out changes incrementally, allowing us to limit the blast radius in case something goes wrong. However, they’re not without limitations. Canary deployments essentially sacrifice a small portion of users for the greater good. But what if you want to gain insights without impacting any real...

In security and access control, authentication and authorization are two distinct yet interconnected concepts. Authentication is the process of confirming the identity of a user or system, while authorization defines the actions that the authenticated user is permitted to perform within your system. Although API Gateway integrates directly with Cognito, it lacks built-in support for fine-grained authorization. In a previous article, we looked at implementing fine-grained authorization using a...

In security and access control, authentication and authorization mean two distinct but related things. Authentication verifies the identity of a user or system. Authorization determines what actions an authenticated user is allowed to perform in your system. API Gateway has built-in integration with Cognito, but it doesn’t provide any fine-grained authorization out-of-the-box. By default, a Cognito authorizer only checks if a user’s bearer token is valid and that the user belongs to the right...