|
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 Lambda authorizer and Cognito groups. In that approach, authorization takes place on the API side: the caller sends its ID token to the API, and the Lambda authorizer generates a policy based on the user’s groups, which are embedded in the ID token by default. This time, we’ll look at a different approach – using access tokens with scopes. In this setup, the identity provider (Cognito, in our case) manages both authentication and authorization, offloading these responsibilities from the API. Customizing Cognito access tokensAs of December 2023, Cognito supports customizing access tokens [1]. Previously, you could only customize the ID tokens with the Pre-Token Generation trigger [2]. This new capability lets you customize the access tokens by adding specific scopes [3]. Here’s how: 1. Enable Advanced Security Features: Turn on this setting in the user pool. 2. Configure the Pre-Token Generation trigger: Choose “Basic features + access token customization” in the “Trigger event version”. Note: CloudFormation doesn’t support this setting and requires manual configuration. 3. Implement the pre-token generation Lambda function: Use this function to add custom scopes to the access token. Assuming you have two groups in the user pool – You want these groups to correspond to the Your pre-token generation Lambda function might look like the following, where we map the group names to an array of scopes. The Map scopes to API Gateway routesTo ensure API Gateway respects these scopes, configure your API Gateway methods with an These scopes are used with a Cognito authorizer to authorize a user request. A user request is authorized if any of the Here’s how you can configure the For a working demo, check out this repo [4]. ConsiderationsThis is an elegant solution. There is a lot to like about it. But it has one BIG downside – cost. The cost implicationEnabling Advanced Security Features significantly increases the cost of using Cognito: 1. 10x increase in cost: Advanced Security Features cost ten times more than the standard monthly active users (MAU) pricing. 2. No free tier: Unlike the standard MAU cost, which includes a generous free tier of 50,000 MAU, there is no free tier for Advanced Security Features. 3. Still have to pay the standard MAU cost: The Advanced Security Features cost is charged in addition to the standard MAU cost, although you benefit from the 50,000 MAU free tier. The cost overhead is substantial when you enable Advanced Security Features, as detailed in my last post [5]. At 50,000 MAU, you’d pay $2,500 per month, vs. $0 if you use ID tokens for authorization. At 100,000 MAU, it becomes $4525 (using access tokens) vs. $275 (ID tokens). Sadly, other vendors would charge you even more, as one of Cognito’s greatest strengths is its cost-efficiency. Are access tokens more secure than ID tokens?Proponents of this approach argue that access tokens should be used for authorization and ID tokens for authentication. While this might be technically accurate, it has little practical impact. As discussed in my last post [5], ID tokens are just as secure as access tokens. Is this approach faster than Lambda authorizers?Another argument is that this approach is more performant since it eliminates the need for Lambda authorizers and their associated cold starts. However, since you still need a Lambda function to customize the access token, the potential for cold starts remains on the critical path. ConclusionIt’s nice that this approach keeps your authorization logic within the Cognito User Pool setup. It centralizes both authentication and authorization concerns in one place. However, the cost implications are too significant. Unless you’re using Advanced Security Features already, or your application has a high value per user (e.g. a B2B enterprise application), this approach may be difficult to justify in terms of return on investment. Links[1] Cognito now support the ability to customize access tokens [2] Cognito’s Pre-Token Generation trigger [3] How to customize access tokens in Amazon Cognito user pools [4] Demo repo [5] Is it safe to use ID tokens with Cognito authorizers? Related articles
Get 10% off the AWS SA BootcampA friend of this newsletter, Raj Saha (Principal Solutions Architect at AWS), is running a bootcamp to help you land a Solutions Architect job, and has kindly offered us a 10% discount. AWS SA Bootcamp is the most direct and guided path to become a solutions architect and get a high-paying cloud job in 3 months
To learn more about the SA Bootcamp, go to www.sabootcamp.com. |
Join 17K readers and level up you AWS game with just 5 mins a week.
Lambda Durable Functions comes with a handy testing SDK. It makes it easy to test durable executions both locally as well as remotely in the cloud. I find the local test runner particular useful for dealing with wait states because I can simply configure the runner to skip time! However, this does not work for callback operations such as waitForCallback. Unfortunately, the official docs didn't include any examples on how to handle this. So here's my workaround. The handler code Imagine you're...
Lambda Durable Functions is a powerful new feature, but its checkpoint + replay model has a few gotchas. Here are five to watch out for. Non-deterministic code The biggest gotcha is when the code is not deterministic. That is, it might do something different during replay. Remember, when a durable execution is replayed, the handler code is executed from the start. So the code must behave exactly the same given the same input. If you use random numbers, or timestamps to make branching...
Hi, I have just finished adding some content around Lambda Managed Instances (LMI) to my upcoming workshop. I put together a cheatsheet of the important ways that LMI is different from Lambda default and thought maybe you'd find it useful too. You can also download the PDF version below. Lambda default vs. Lambda managed instances.pdf