JWT validation: how-to and best libraries to use
Learn about JSON Web Token (JWT) validation, why it’s important, what the best practices are, and how to do it using trusted third-party libraries.
JWT, which stands for JSON Web Token and is pronounced “jot”, is an open standard for securely sharing JSON data between parties. JWTs are widely adopted in modern web development and used in authentication and authorization workflows.
However, JWTs must be handled carefully if we want our apps and users to stay safe. We need to ensure that the JWT can be trusted and hasn’t been tampered with and validate several token elements.
In this article, we will discuss JWT validation and some of the best libraries you can use. But first, let’s review the basics of JWTs.
JWT 101
A JSON Web Token (JWT) is an open standard for securely transmitting information between different systems as signed JSON objects. JWTs are commonly used in the OAuth 2.0 and OpenID Connect (OIDC) protocols.
A JWT consists of 3 parts:
- Header: Specifies the token type (JWT) and the signing algorithm used to create the token’s signature (like HMAC SHA256 or RSA).
- Payload: Contains the claims – pieces of information about the user. There are standard claims (which are registered with the Internet Assigned Numbers Authority (IANA) and defined by the JWT specification) and custom ones (which are used to represent the information we want our JWT to contain, e.g., the user’s email or profile picture). Some examples are:
- sub: Standard claim that specifies the subject of the JWT, for example, a user ID.
- iss: Standard claim that specifies the issuer of the JWT.
- aud: Standard claim that specifies the recipient for which the JWT is intended.
- exp: Standard claim that specifies the time after which the JWT expires.
- email: A custom claim that contains the user’s email.
- picture: A custom claim that contains a link to the user’s profile picture.
- Signature: A signature is used to verify that the sender of the JWT is who they say they are and to ensure that the message wasn't tampered with along the way.
Each part is base64url-encoded and concatenated using dots: encoded_header.encoded_payload.encoded_signature.
An example JWT looks like this:
If we decode this JWT, we will get its individual parts.
For more information on JWTs, check out JSON Web Tokens.
Protecting JWTs: JWS, JWE, and JWK
JWTs can be protected via JSON Web Signature (JWS) or JSON Web Encryption (JWE).
- JWS uses a signature algorithm and is used to share data between parties when confidentiality is not required. This is because claims within a JWS can be read as they are simply base64-encoded (but carry with them a signature for authentication). JWS supports symmetric key-based MACs (single key used to sign and verify) and asymmetric key-based digital signatures (private key used to sign, public key used to verify).
- JWE uses a signature and encryption algorithm and guarantees confidentiality (i.e. ensures that only the receiver can decrypt data). Claims in a JWE, are encrypted and entirely opaque to clients using them as their means of authentication and authorization. JWE supports both symmetric key cryptography (single key used to encrypt and decrypt) and asymmetric key cryptography (public key used to encrypt, private key used to decrypt).
Both JWE and JWS operations expect a JSON Web Key (JWK). A JWK is a JSON data structure that represents a cryptographic key. Using a JWK rather than one or more parameters allows for a generalized key as input that can be applied to a number of different algorithms that may expect a different number of inputs.
Another term you might come around while working with JWTs is JWA: JSON Web Algorithms. JWA defines the cryptographic algorithms that JWE encryption and JWS signing can use. Some examples are:
- HS256: HMAC using SHA-256
- RS256: RSASSA-PKCS1-v1_5 using SHA-256
- A256GCM: AES GCM using 256-bit key
How to validate a JWT
Every time your app receives a JWT, you must validate it. This is the number one best practice to have in mind. You should never implicitly trust a JWT, even if you operate within an internal network without internet access.
You can use any of the following ways to validate a JWT:
- Use a middleware for your web framework.
- Use a third-party library.
- Manually implement the checks described in the JWT spec.
Verifying and validating a JWT includes the following steps.
- Parse the JWT to extract the header, payload, and signature.
- Verify the signature using the secret key or public key.
- Check the expiration time (
exp
) and the not-before time (nbf
) claims to ensure the JWT is valid. - Verify the issuer (
iss
) claim to ensure the JWT was issued by a trusted party. - Verify the audience (
aud
) claim to ensure the JWT is intended for the correct recipient.
Third-party libraries for JWT validation
We strongly recommend using middleware for your web framework or a third-party library for JWT validation instead of rolling out your own custom implementation. Avoid implementing JWT from scratch, as cryptography and security are very complex topics—even for experienced developers.
In this section, we list our favorite libraries for some of the SDKs we support. If you don’t want to use one of these, you can refer to jwt.io for an extensive list of libraries for token signing and verification for various languages.
Remember to follow the library’s instructions, check out for security notices, change default settings where applicable, and refer to the library’s documentation for the latest code samples.
Validate JWTs with Node
For all things JavaScript, the jose library is great and widely used. It supports JWTs, JSON Web Signature (JWS), JSON Web Encryption (JWE), JSON Web Key (JWK), and JSON Web Key Set (JWKS) and has zero dependencies.
This is an example of validating a token using a public JSON Web Key Set hosted on a remote URL.
For more examples, refer to the jose repo readme.
For an example of validating a token using AuthKit and Next.js, see this repo.
Validate JWTs with Golang
jwt-go is a great Golang implementation of the JWT spec. To install the package, run go get -u github.com/golang-jwt/jwt/v5
.
Let’s see an example of parsing and validating a token using the HMAC signing method.
You can also use certain validators to check specific claims of the JWT. For example, WithIssuer(ISSUER)
will check if the JWT’s issuer matches the input argument ISSUER
.
For more details and examples, check the jwt-go docs.
Validate JWTs with Python
PyJWT is a popular Python implementation of the JWT spec. To install the package run pip install PyJWT
.
To verify a token call the decode
method passing the JWT, the signing key, and the algorithm.
decode
will verify the JWT signature and return the token claims. Alternatively, you can use decode_complete
which returns a dictionary containing the token header (JOSE Header), the token payload (JWT Payload), and token signature (JWT Signature) on the keys “header”, “payload”, and “signature” respectively.
For more details and examples, check the PyJWT docs.
Validate JWTs with Ruby
JWT is a popular Ruby implementation of the JWT spec. To install the gem run gem install jwt
.
To verify a token call the JWT.decode
method, passing the algorithm used in the options hash. In this example we are using RS256
.
Validate JWTs with PHP
PHP-JWT is a popular PHP implementation of the JWT spec. To download the package run composer require firebase/php-jwt
.
To verify a token use the JWT::decode
method and then proceed to verifying the claims.
Validate JWTs with Java
The jose.4.j library is an open-source implementation of JWT and the JOSE specification suite.
You can verify the signature using verifySignature
. Let’s see an example of signature verification using JSON Web Signature (JWS).
To validate and process a JWT, you must use JwtConsumerBuilder
to construct an appropriate JwtConsumer
.
For more details and code examples, see the jose.4.j docs.
Validate JWTs with .NET
IdentityModel Extensions for .NET is Microsoft’s library for JWTs. The validation steps are captured into Validators, which are all in one source file. The library has the following validators:
ValidateAudience
: Ensures that the token is indeed for the application that validates the token.ValidateIssuer
: Ensures that the token was issued by a STS I trust.ValidateIssuerSigningKey
: Ensures the application validating the token trusts the key that was used to sign the token.ValidateLifetime
: Ensures that the token has not expired.ValidateTokenReplay
: Ensure the token is not replayed (this is a special case for some onetime use protocols).
Validators can be turned off, but this is not recommended.
Let's see an example of JWT validation using this library.
Best practices for JWTs
No matter how you choose to handle your JWTs, make sure to follow these best practices to keep your users safe.
- Keep the secret key safe: Keep the secret key used to sign the JWT confidential. Use a key management system or store the key in a secure environment variable.
- Always validate JWTs: Always validate a JWT before using it.some text
- Verify the signature using the secret or public keys to confirm the token’s authenticity.
- Validate the algorithm that was used.
- Check the expiration time (exp) and the not-before time (nbf) claims to ensure the JWT is valid.
- Verify the issuer (iss) claim to ensure the JWT was issued by a trusted party.
- Verify the audience (aud) claim to ensure the JWT is intended for the correct recipient.
- Keep payloads small: Avoid storing sensitive information in the payload, and consider limiting the number of claims to only essential data.
- Keep JWTs secret: JWTs are signed JSON objects that contain user information. They can include sensitive data such as user IDs, roles, and permissions. If an attacker gets hold of a JWT, they can use it to impersonate the user and gain unauthorized access to your application. Therefore, it's crucial to keep JWTs secret and ensure that only authorized parties can access them. To keep JWTs safe, ensure they are transmitted securely over the network using HTTPS and store them securely on the client side.
- Use secure libraries: Utilize well-established libraries and frameworks for creating, parsing, and verifying JWTs. Avoid implementing JWT from scratch, as cryptography and security are very complex topics—even for experienced developers.
- Use strong encryption and algorithms: Choose robust asymmetric algorithms (like RSA or ECDSA) for signing JWTs. They are generally considered the best, as they use a public/private key pair, making it difficult for an attacker to forge tokens. The most widely used option, supported by most technology stacks, is RS256. If you really need to use symmetric keys, then choose HS256 (HMAC using SHA-256) — though using symmetric keys is not recommended.
- Use short lifetimes for tokens: Have your JWTs expire after a short period of time to reduce the window of opportunity for misuse in case a token is compromised. To not sacrifice UX, implement session management with refresh tokens that live longer. When you generate JWTs make sure to set a short expiration time.