A JSON web token (aka JWT, pronounced “jot”) is an open standard that securely relays information between clients and servers as a compact, self contained JSON object.
So, what exactly does this mean?
At a fundamental level, web applications pass data back and forth between the client and the server. JSON web tokens are a form of secure communication between the two.
Think of receiving a card in the mail from your aunt. The envelope is sealed, so you know that she chose this dog in a party hat, and you received the message (happy birthday!). Now you can send your own thank you note back to her. A successful exchange of information in tamper-evident containers.
In the case of online communication, JWTs can be thought of as the signed card, the sealed envelope, and the sender’s information on the envelope all in one.
Authentication and authorization are two specific, related types of data exchange.
Authentication is the process by which applications verify a user is who they say they are, while authorization is the process by which applications verify what that user is or is not allowed to do and access within an application.
When a user successfully logs in to your application, an API call is sent from their user object to the client’s authentication server. That initial API call includes login credentials (core to authentication), which are typically tied to specific access permissions (core to authorization). Once the user is in, however, subsequent API calls won’t include those login credentials or permissions – how does the client know it’s still them, and what they’re allowed to do within the application?
JSON web tokens are a fast, efficient way to answer those questions securely – they keep users in an authenticated state while dictating how they are authorized to engage with an application (i.e., permitted actions, routes, etc.).
JSON web tokens include three parts: the header, the payload, and the signature, each a Base64Url encoded string. The final output is formatted like this: header.payload.signature
The header contains two parts: the type of token (here it’s a JWT token) and signing algorithm (commonly a HMAC SHA256 or RSA).
The header is finalized by Base64url encoding the token and signing algorithm.
The payload consists of one of three claims – registered, public, private – that hold the user’s information.
These claims are the core information that JWTs transmit. The types of claims included in the payload determine which information the JWTs communicate (i.e., user identity, permissions, expiration of JWT, to name a few).
For example, a subject claim lets you know which user is the subject of the JWT or an expiration claim lets you know until when a JWT can be accepted.
The payload is finalized by Base64url encoding the claim. You can learn more about claims in our article, JWT claims.
The signature is created by hashing the combination of header and payload with a secret key.
The signature is the JWT component used to verify user identity. A consistent JWT across client requests confirms the API calls come from the same user.
The ultimate JWT will consist of three Base64Url encoded strings connected with dots:
Once the server has constructed the JWT, it will send the final product to the client to store.
Now that we know what JWTs look like, let’s talk about how to use them. Although JSON web tokens can be used to exchange information in a variety of use cases, at Stytch we value them for their applicability in authentication and authorization.
Between the token’s header, payload, and signature, a JWT can comprehensively verify the user themself, what they’re authorized to do, and the integrity of the data. Storing this user data client side, as opposed to in sessions on the server, is called stateless authentication.
You may have seen sessions used to manage similar situations in auth. You can read more about the differences between sessions and JWTs on our blog, but generally the difference can be summed up as follows:
Session-based auth relies on the server to create and maintain a record of a user’s authentication, as well provide a way for the client to reference it on each request.
Here’s how a JSON web token is created and used:
Zooming out from the mechanics, there are benefits to managing user access with JWTs along with a drawback to consider.
JWTs hold all information needed for user auth in a small token.
This self-containment eliminates reliance on the server and database, which in turn, reduces latency in the application and the need for server-side storage – a real asset for applications where responsiveness is top of mind for user experience.
The compactness of the tokens also speed things up – all claims are only three characters to keep length short!
Self-contained JWTs also allow developers to authenticate users across external applications. The signatures and identity information within a JWT allow for server-to-server applications to self-sign and refresh tokens without the user needing to re-enter credentials.
Take OAuth for example. When your aunt bought your birthday card, she logged in to Hallmark’s website using Google OAuth. This means her user information was shared across three servers – her own client server, Google’s server, and Hallmark’s server – in the form of a JWT.
These separate applications passed the token around, securely transmitting information, to authenticate your aunt’s identity and authorize her to purchase your birthday card using information from her Google account, all in seconds.
Signed tokens cannot be invalidated or updated. This means that a valid signature in an unexpired token will always allow users to access protected resources.
The effects of the JWT’s independence from the server range from inconvenient to a security threat.
For example, user requests such as “log me out of all devices” or role-based authorization changes will not be reflected until the existing access token has expired. Waiting five minutes (Stytch’s default token lifetime) for these changes to take effect is potentially annoying, but okay.
The real problem comes from compromised JWTs. No matter how quickly you take action server-side, there will always be a lag. This gives bad actors a window where they can act as the user and the only thing that can stop them is the expiration window locked in the token.
This means that JWTs’ greatest asset – its safeguarded information – is also its biggest vulnerability.
That said, there are many security measures and steps companies can take to protect user accounts, while still reaping the benefits of JWTs. To learn more about those, you can dive deeper into our blog comparing JWTs and sessions, and best practices for working with each.
Stytch’s API and SDKs support JSON web tokens. Or if session cookies alone better serve your use case, Stytch offers this method, too.
Alternatively, you can have the best of both worlds – want the flexibility of JWTs with the security of Stytch’s servers on sensitive requests? This combination is possible with our step-up-auth!