Skip to content

Instantly share code, notes, and snippets.

@pgolding
Last active August 17, 2023 08:34
Show Gist options
  • Save pgolding/fedb0d88b560eabe3cd7a1ff4d38bda1 to your computer and use it in GitHub Desktop.
Save pgolding/fedb0d88b560eabe3cd7a1ff4d38bda1 to your computer and use it in GitHub Desktop.
How to use pyjwt to decode RS256-signed JWT tokens (e.g. for Auth0) and run it on AWS Lambda with Python 3.6 (e.g. custom authorizers for serverless)

PyJWT with Python AWS Lambda Functions (LF)

If you are using Auth0 (or some OAuth authorization service) then you will most likely be interested in using JWT tokens via some kind of grant. Auth0 discusses how to call an API with such a token.

Perhaps you wish to use a custom authorizer for your serverless project.

To do so, you must write code to decode the JWT token before creating a policy (or not) to grant invoke permissions on your LF. Per various recommendations, the best method to protect your JWT tokens is to use RS256 signing.

However, if you are using pyjwt to decode RS256 tokens, this library depends upon cryptography and that, in turn, has compiled dependencies. If you try something like pip install cryptography -t . or pip install pyjwt[crypto] -t . to install the dependencies into your serverless project on OSX, then you will find that it doesn't work when you deploy on AWS.

You might see an error, something like:

No module named '_cffi_backend'

This is because pip looked at your machine and decided that you need the OSX compiled dependencies. However, LFs run on Linux.

To solve the issue, you should find a Linux version of the installation package(s) that work with AWS Lambda's environment, as described in principle in this AWS article.

For installing cryptography in particular, you can do the following:

  1. Install JWT as per usual into your serverless project - pip install jwt -t .
  2. Visit the cryptography PyPi downloads page and download the appropriate -manylinux1_x86_64.whl package for your version of Python and save it in your serverless project.
  3. Decompress the wheel file into your project unzip <your_wheel_file>
  4. Visit the cffi PyPi downloads page and choose the relevant .whl package
  5. Decompress the wheel file into your project unzip <your_wheel_file>
  6. Install the asn1crypto dependency locally: pip install asn1crypto -t .

Now you have all the components needed to decode a RS256 JWT in your AWS LF using Python.

If using RS256, you will need to have your public key. For example, this will be available via Settings > Advanced Settings in your Auth0 application, assuming you use Auth0. You need to look under the tab Certificates where you will find the certificate and an option to download. You should download as a PEM to your serverless project.

However, you will not be able to use the PEM directly in your Python. You first need to convert it to a public key. You can do this using:

openssl x509 -pubkey -noout -in cert.pem > pubkey.pem

You can then open the pubkey.pem and paste it as a string into your Python code, something like:

public_key = b'-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEAC...'

It is now available for you to decode the JWT via the Authorization Bearer <jwt_token> header which is exposed to your custom authorizer in the event variable: event['authorizationToken']

You can now decode your JWT:

tok = str(event['authorizationToken'])
jwt_token = tok.split(' ')[1]
audience = 'audience_set_in_api_on_auth0'
decoded = jwt.decode(jwt_token, pk, audience=audience, algorithms='RS256')

Of course, you might want to add various error handles to the above, but you get the idea.

Cheers, and happy JWT decoding.

@greg-kennedy
Copy link

What is the purpose of the asn1crypto library? Is it for converting downloaded PEM to a usable public key? I'm retrieving public key from remote .well-known and this layer seems to work fine without it...

@pgolding
Copy link
Author

I don't recall exactly without checking my set-up. It might be an artifact of my particular project. It's not needed for PEM decoding per se as Cryptography has a method for that. If your project works fine without it, then great.

@emilian
Copy link

emilian commented Aug 25, 2022

I followed the instructions but still couldn't get this to work on my Macbook. Kept getting Internal Server Errors on my lambda funtction. What fixed the problem was installing everything on a Linux container, and then zipping everything up and uploading it as a layer to Amazon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment