Serverless custom authorizer issues on AWS.

Will Bowman
Feb 16, 2018 · 2 min read

If you google around you’ll find plenty of examples on how-to create a custom authorizer for serverless lambda events.

I used this example when I was building mine:

// Return an IAM policy document for the current endpoint   
const effect = isAllowed ? 'Allow' : 'Deny';
const userId = user.username;
const authorizerContext = { user: JSON.stringify(user) };
const policyDocument = utils.buildIAMPolicy(userId, effect, event.methodArn, authorizerContext);

I ran into a couple issues after deploying and thought I might share them.

User is not authorized to access this resource

“Message”: “User is not authorized to access this resource”

After some debugging I noticed the error was not coming from my authorizer but from AWS itself and after redeploying it would go away. I could hit 1 route but not another after.

A bit of googling later I ran across this post that explains what I was seeing:

You may be seeing cached results. The policy generated by the Lambda function should apply to the entire API (all resources/methods), and caching is enabled by default with a TTL of 300 seconds.

Basically the cache key is made up of (token + restApi + authorizer + stage + deployment).

The problem

All of these examples are sending event.methodArn for your policies resource.

This includes the method and route:


Since your cache key does not take your method or route into consideration your authorizer will be used on other methods and routes. Since those are not validated with methodArn the user will be denied access with “User is not authorized to access this resource”.

The solution

Instead of sending event.methodArn you can send a wildcard as noted in the article:

context.succeed(generatePolicy('user', 'Allow', '*');

Or build out your policy:

context.succeed(generatePolicy('user', 'Allow', [

I’d rather keep users locked down to the specific API so I’d generate something like this from env variables:

context.succeed(generatePolicy('user', 'Allow', 'arn:aws:execute-api:us-1:abc:123/prod/*');

Or something more dynamic:

event.methodArn.split('/').slice(0, 2).join('/') + '/*'

“message”: null

When using an invalid, or missing token AWS kept reporting:

“message”: null

The problem

Debugging locally with serverless-offline I can see in the console:

Serverless: Running Authorization function for get /user (λ: auth)
Serverless: Authorization response did not include a principalId: (λ: auth)

This is related to the examples sending Unauthorized as the error to the callback.


Serverless responds correctly, with a 401, but in deployment it does not work.

The solution

Denying access to the resource got rid of the errors on AWS and serverless-offline. While I would prefer to receive a 401 response the 403 will have to do for now.

context.succeed(generatePolicy('user', 'Deny', event.methodArn);

A day-to-day log of the questions we’ve asked & the answers…

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store