Authentication

All You Need to Know About JWT Authentication

JSON Web Token (JWT) is a widely-recognized standard for user authentication (RFC 7519), enabling secure information exchange online as a JSON object. JWT comprises three parts: the header, detailing the encryption algorithm; the payload, containing ‘claims’ or transmitted information; and the signature, used for verifying the data’s authenticity. It’s a self-contained and digitally signed method, ensuring the transmitted information can be trusted. 

This article further explores JWT authentication’s key use cases, explains its operational mechanism, and offers best practices for effective implementation.

What Is JWT Authentication?

A quick refresher before we get started. A JWT is essentially a JSON-encoded representation of a claim, which may be transferred between two entities. The claim is signed digitally by the token’s issuer. The recipient party of this token may use this digital signature to demonstrate ownership in the future. 

Signed tokens can be used for authentication by verifying the genuineness of the claims they are attached to. Encrypted tokens, on the other hand, conceal those claims. When tokens are signed via private/public keys, a signature also guarantees that the party with the private key alone has signed it.

The following are scenarios in which JWT may be helpful:

  • Authentication – This is the most prevalent scenario. After the user has logged in, every following request will feature the JWT, letting the user access services, routes and resources allowed with the token. Single Sign On (SSO) commonly uses JWT today, because of its minimal overhead and its ability to be smoothly employed across various domains.
  • Information Exchange – JWT is one of the most effective ways of securely exchanging data between parties. For instance, a JWT may be signed using private/public key pairs to confirm the sender’s identity. Furthermore, as the signature is attained using the payload and the header, it is possible to verify that the content has not been compromised. 

Read our detailed guide about Authentication vs Authorization

JWT Components

JWTs have three main components: signature, payload, and header. Each is distinguished from the other via dot (.), and will adopt the following format.  

1. JWT Header

The information featured in the header outlines the algorithm utilized to create the signature. The decoded form of the header should look like:  

<code>{
alg”: “HS256,
typ”: “JWT
}</code>

Please note that HS256 is the hashing algorithm HMAC SHA-256 employed to produce the signature in the example above.

2. JWT Payload

All JWT authentication claims are retained here. Claims are employed to authenticate the party that receives the token. For instance, a server may set a claim that says ‘isAdmin: true’ and give it to an administrator once they manage to log into the application. The administrative user is now able to use this token in all consequent requests they send to a server to verify their identity. 

The decoded form of the payload see in the JWT example is as follows:  

<strong><code>{
sub”: “1234567890,
name”: “Jill Smith,
iat”: 1516239022
}</code></strong>

The “name” field is employed to identify the individual to whom the token was given to. The “sub” and “iat” are instances of registered claims and are shortened forms of “subject” and “issued at”.

3. JWT Signature

The signature component of a JWT is gained from the payload and header fields. The processes involved in developing this signature are outlined below: 

  1. Unite the base64url encoded representation of header and payload with a dot (.)
    base64UrlEncode(header) + “.” + base64UrlEncode(payload)
  2. Hash the data above with a secret-key only revealed to the server that issues the token. The hashing algorithm is the algorithm described within the header.
    hash_value = hash([base64UrlEncode(header) + “.” + base64UrlEncode(payload)], secret-key)
  3. Base64Url encode the hash value gained from the above step.
    Signature = base64UrlEncode(hash_value)

Since the “secret-key” is only revealed to the server, only it can issue new tokens with an authentic signature. Users can’t forge tokens and create a valid signature, as the token demands knowledge of the “secret-key”.  JWTs exist in different authentication mechanisms. These are generally passed in the “authorization” header at the time a user submits a request to the client. 

When Should You Not Use JSON Web Tokens?

The use of JWTs for session tokens may be appealing at first, given that: 

  • You can retain any sort of user details on the client
  • The server can trust the client as the JWT is signed, and there is no need to call the database to retrieve the information you stored in the JWT
  • You don’t have to coordinate sessions in a central database when you reach the inevitable issue of horizontal scaling

However, JSON Web Tokens shouldn’t be used as session tokens as a default. There are many reasons for this. Here are a few important ones you must know: 

  •  A JWT has a large range of features and a wide scope, which raises the potential for errors, either through users or library authors. 
  • You can’t get rid of a JWT at the end of a session, because it is self-contained and no one authority can deem it invalid. JWTs are also large. When employed with cookies, this means a lot of overhead per request. 
  • There is a significant cost connected to implementing and using JWTs—they are sent for each request to the server and this is always a large cost in comparison to server-side sessions. 
  • While there are less security risks with JWT when compared to Hypertext Transfer Protocol Secure (HTTPS), a JWT can still be intercepted and the information is deciphered, revealing the user’s information. 

If you have a database for your app, a better option is to employ a sessions table and use consistent sessions offered by the server-side framework you select.

Related content: Magic Links

JWT Authentication Best Practices

Consider applying the following practices when using JSON Web Tokens.

1. Validate Tokens

Always validate incoming JWTs, even within an internal network where the Authorization Server, Resource Server, and Client are offline. Don’t rely on your environment settings for security. If using a public domain, you have to deal with a different threat model, which requires extensive security measures. Validating tokens from the start protects you from attempts to breach your network.

The only instance when you don’t need to check a token’s signature is when you first receive it in the response from the Authorization Server’s token endpoint. 

2. Check the Audience Claim

The Resource Server should always check a token’s audience claim in the token against a whitelist. Any request with a token intended for a different audience should be rejected. Access tokens should include the URL of the API they were issued for. ID tokens must include the client ID in their aud claims. Tokens must be decoded for the client to be able to use the data they contain.

Tokens should be passed on to the intended audience only to mitigate attack vectors that leverage a legitimate server to pivot to another server. 

3. Ensure That All Tokens Are Used Correctly

JWTs are versatile. They can serve as ID tokens or access tokens. You need to distinguish the different intended uses of each token. Don’t accept an unintended use for a JWT, such as an access token being used as an ID token. To ensure tokens are used correctly, check their scope (ID tokens don’t have any). Check the different audience claim values to determine the token type. 

You may use the value of that claim to verify the token type. Set a purpose claim for tokens via the Curity Identity Server. 

4. Avoid Symmetric Signing

In general, you should always try to avoid using symmetric signing. Symmetric keys require all parties to know the secret, making it harder to protect. It is also difficult to know who has signed the keys. With asymmetric keys, you know that the JWT was signed by the individual with the private key. With symmetric signing, anyone who can access the secret can sign the tokens.

5. Watch Out for XSS and CSRF Attacks

Don’t store the token on cookies. Wait, so what’s left? That doesn’t mean that you have to give up on cookies altogether. Just do the following:

  • httpOnly: Simply make the cookie inaccessible via JS, a mandatory move while creating cookies. Make them immune to (malicious) user code.
  • SameSite Policy: Cookies are sent on every request, unless of course, the browser is new and that the SameSite policy of your cookie is empty. Use a Lax value to send your tokens to be sent to different domains if needed. You can then keep making GET requests and stay with the option to make redirections as per your requirements, but not POST ones anymore.

Related: Password Authentication is Becoming Outdated 

There are very few use cases where you really must use symmetric signing today. If doing so, it’s best to employ secrets to increase security.

JWT Authentication with Frontegg

Frontegg’s authentication infrastructure is based on JWT by design. We have implemented our JWTs to match the highest security standards in the industry. This helps us be fully compliant with all common protocols like OpenID Connect 1.0 (OIDC) and OAuth2. In other words, the Frontegg user management offering covers all security and compliance bases for you.

Also, Frontegg’s authentication will allow you to easily integrate between your app and other third-parties. You can do so while leveraging our well-known JSON Web Key Set (JWKS) endpoints, while relying on the public certificate and refresh tokens that come along with the JWT mechanism. It’s not surprising that Frontegg has become a proven and tested development accelerator.

That’s not all. With Frontegg, it takes just five minutes to make your application fully JWT protected. Feel free to contact us to get started.