AWS Lambda Custom Authorizer
Tags: aws, lambda, node, async
Published: 2023-06-20 03:42:40

If you are like me you probably struggled to get custom authorizers working in Lambda. It probably isn't because you are too dumb to understand, it is because of magic. Magic is great if everything works as expected.  When it doesn't, though, it makes debugging an absolute nightmare.

There are four things you absolutely **need** to get right when working with custom authorizers:

1. Return the correct policy document.

    This one was probably the biggest oversight on my part. In order for your custom authorizer to essentially forward the request to your Lambda it needs to return a valid policy document.  In short, the policy document returned by the authorizer function is evaluated by API Gateway to determine whether the client is authorized to access the requested resource.

    The [example](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html) in the AWS docs works well and you can simplify it as needed.

2. Callbacks vs async/await

    Many of the custom authorizer examples (even more recent ones) were written with callbacks in mind.  For example, you'll see most custom authorizer functions defined with the `callback` argument and then a response starting like `callback(null...)`, ironically indicating success.  Ok.  Searching about how to convert this to using async/await was oddly time-consuming, especially considering I thought this would be a problem many people would've run into.

    Eventually I found what I was looking for, courtesy of [stackoverflow](https://stackoverflow.com/questions/55106223/lambda-authorizer-response-using-async-await-in-node-js/60280752).  The answer was comically simple, just return the policy document object or throw an error.

    Great, no more callbacks.

3. `throw new Error("Unauthorized")`

    Think you can just return whatever error you want based on your specific domain model?  So naïve.  AWS is very specific in the errors you can return but to their credit it is [documented](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html).  Again, this was another area where I spent more time than I care to admit agonizing about why my Lambda wasn't returning the error code I expected.

4. CORS

    Of course, a "gotchas" list like this wouldn't be complete without an entire section on CORS.  Once I solved 1, 2, and 3, I assumed I'd be off to the races only to be presented with a CORS error (using the one and only [Swagger UI](https://swagger.io/tools/swagger-ui/) to interact with my API like a true developer).

    Traditional Lambdas allow you to arbitrarily return payloads (including headers) but with custom authorizers this is not possible.  Using [Serverless](https://www.serverless.com/) (an incredible tool, btw), I learned you need to configure your API Gateway to respond with the proper CORS headers in certain situations, specifically 4xx and 5xx responses from a custom authorizer.  This [guide](https://www.serverless.com/blog/cors-api-gateway-survival-guide/#cors-with-custom-authorizers) was pivotal to me breaking through the final barrier to a working solution.

Now, each of these problems on their own don't sound so significant but when you encounter all of them at once and you don't know what you are doing to start with, it can feel like climbing a mountain.  Granted, I probably could've read the documentation more closely but there were a lot of disjointed examples out there that only covered one or two of the four potential pitfalls I ran into.

After all is said and done I am now the proud owner of a robust authorizer middleware that I can easily add to any of my existing Lambda functions and I was able to share my experiences with everyone here.