If you give a dev a lambda

Sharib Jafari
5 min readOct 31, 2023

This post is part of a series of posts I’m writing as part of my“build in public” project.

If You Give a Mouse a Cookie

Context

I’m experimenting with making a small social media post scheduler, publicly. If you’ve been reading my posts on this topic, you know my progress (and frustrations) with access and authentication. The good news is that I’ve solved this piece of the puzzle and moved on.

In this post, I’ll discuss the problem I faced with using the Cognito user pool authorizer, the solution I came up with (the title probably already spoils it for you), and how I took it one step further.

Problem of redirection

The good thing about using the Cognito User pool was the ability to use the CognitoAuthorizer out-of-the-box. As long as I make sure to set the correct ID token as the authorization header, CognitoAuthorizer can validate the token and grant authorized access to my API.

On the client side, I can store the ID token in local storage or as a cookie and have a simple JavaScript code to make sure it’s included as an authorization header in each request made by the client.

The issue arises when the backend is called in response to a redirection.

In my case, I was using my protected Auth Endpoint (responsible for authorizing access to LinkedIn so I can publish posts on the user's behalf) as the redirection URL for authorization flow with LinkedIn. When LinkedIn redirected the browser to my API, the browser couldn’t set the authorization header and CognitoAuthorizer rejected the request.

Auth can’t hurt you if auth doesn’t exist

The simplest solution, of course, is to provide UNRESTRICTED ACCESS to this endpoint.

As shown above, if I get rid of the CognitoAuthorizer, I can simply fetch the ID token from the cookie when the browser is redirected to my endpoint. This ID token still needs to be validated and the endpoint lambda needs to have the validation logic.

Since this is the only endpoint that is used for re-direction, I might get away with making this endpoint accessible (with appropriate throttling and probably behind a Shield/WAF). I can simply use CognitoAuthorizer for the rest of my endpoints.

But wait… there’s a (slightly) better way.

Lambda authorizer to the rescue

Another solution is to use a Lambda Authorizer (formerly known as a custom authorizer).

It’s exactly the same as the first solution, except that the logic for token validation is now moved from my endpoint to the authorizer lambda. This helps me separate the authentication code from the actual code and my endpoint is now officially behind an authorizer.

I can also decide to use this authorizer for all my endpoints although, at this point, it doesn’t offer any advantage over the CognitoAuthorizer except maybe some uniformity.

If you give a dev a lambda

In a very popular children's book by Laura Numeroff called If You Give a Mouse a Cookie (not related to the browser cookies), the simple act of giving a mouse a cookie transpires into a domino effect that ends up with the mouse doing a lot more than simply eating the cookie.
I think developers are kind of like that mouse.

I tried so hard not to use a lambda authorizer and looked for ways to make the CognitoAuthorizer work for me, however, once I settled for a lambda, immediately I wanted to do more with it.

In my previous post, Practicing the Principle of Least Privilege, I described how one can use the Identity pool and tagged session for fine-tuned access control. All of my endpoints require the identity pool to provide them with IAM credentials that can be used to access resources specific to the current user.

Since I was already making a call to cognito in my Lambda Authorizer, I decided to use it not just as an authorizer but also as a proxy that enriches the request with the required IAM credentials.
The idea is to request the credentials from the identity pool and provide them as part of the authorizer request context to the endpoint being called.

If the credentials can’t be created, the endpoint is never invoked and the request fails for authorization. If the credentials are created, they are easily available to the lambda invoked by the endpoint, and the core endpoints never have to deal with the repeated logic of calling cognito and obtaining credentials.

The disadvantage of course will be the added latency and wasted effort of creating IAM credentials if they are not going to be utilized by the called endpoint or if the endpoint returns for an unmet pre-requisite before having to utilize these credentials.

As with any solution, this isn’t a silver bullet. For my limited scope, this solution works well. For you, it might not. But it always helps to know that a lambda authorizer can be repurposed as an enriching proxy.

Conclusion

You cannot use CognitoAuthorizer if you need your endpoint to work as a redirection target since your client can’t set the authorization header in case of a redirection.

You can store the token in a cookie and use a lambda authorizer for validation instead.

You can also repurpose the lambda authorizer to enrich your API calls by adding some required fields (IAM credentials in my case) to the authorizer request context.

If you give a dev a lambda, they’ll probably do more with it than simply authorize!

If you found this post insightful and want to stay updated with more tips and experiences, I invite you to follow me on Medium and LinkedIn for future content.

--

--

Sharib Jafari

Berlin-based software craftsman with 10+ years of experience as a consultant, full-stack developer and solutions architect. Passionate about TDD & Clean Coding.