Stop Guessing: What is a JWT?
JSON Web Token (JWT)
A JWT Is an open standard that defines a compact and self-contained way for performing Authentication in REST APIs where information is securely transmitted between both parties as a JSON object.
This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with HMAC algorithm) or a public/private key pair using RSA.
NOTE 1: We consider it compact because of its size, it is possible to send it through an URL, POST parameter, or inside an HTTP header. Also due to its size its transmission is fast.
NOTE 2: We consider it self-contained because we do not need to query the database more than once, the payload contains all the necessary information about the user.
When to use JWT?
Authentication: After the user is signed in, each subsequent request includes the JWT. This allows the user to access routes, services, and resources that require that token.
Information Exchange: JWTs are a secure way of transmitting information between parties, because you can be sure that the sender is who they say they are, since they can be signed (possibly by using a public/private key pair). You can also verify that the content has not changed, since the signature is created using the header and the payload.
JWT Structure
A JWT is formed by three parts separated by dots (.): a Header, a Payload, and a Signature. These parts follow this structure: xxxxx.yyyyy.zzzzz.
Header
Contains some information that usually include the token type (which is JWT) and the hashing algorithm (such as HMAC, SHA256 or RSA).
Afterwards the JSON containing that Header is Base64Url encoded to form the first part of the JWT.
//Example of a Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload
Contains the claims that are statements about an entity (usually the user) and additional metadata.
NOTE: Can not contain sensible information about a user like password, but it is ok to include user id, name or email.
Example of claims: iss (issuer), exp (expiration time), sub (subject), aud (audience), among others.
Afterwards the JSON containing the payload is then Base64Url encoded to form the second part of the JWT.
//Example of a Payload
{
"sub": "0987654321",
"name": "Jane Doe",
"admin": true
}
Signature
Is used to verify that the sender of the JWT is who they claim to be and to ensure that the message was not changed while it was being transmitted.
To create the signature take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign it.
//Example of a Signature using the HMAC SHA256 algorithm
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
NOTE: A simple way to generate a secret is using http://www.md5.cz/ to generate a MD5 hash of a string.
Uniting the three parts
The output is three Base64 strings separated by dots: an encoded header, an encoded payload and it is signed with a secret. They can be passed in HTML and HTTP environments.
NOTE: Go to jwt.io, a website that allows you to decode, verify and generate JWT.
How does a JWT work?
1 - When the user is authenticated by successfully signing in using their credentials, a JWT will be returned.
NOTE: Keep in mind that tokens are credentials, so you must prevent security issues: do not keep tokens longer than required.
2 - Whenever the user wants to access a protected route, its request should send the JWT, usually in the Authorization header using the Bearer schema: Authorization: Bearer .
NOTE: This authentication mechanism is stateless, because the user state is not saved in the server memory. Instead, the server's protected routes check for a valid JWT in the Authorization header, and only allows the user if this condition is fulfilled. As a result it is not necessary to query the database multiple times as JWTs are self-contained, so it already has all the necessary information.
Why Should You Use JWT?
- They are stateless: Since tokens are self-contained they have all the information that is needed for authentication. This is good for scalability as your server does not have to store session state.
- They can be generated from anywhere: Token generation and token verification are decoupled. This allows you to handle the signing of tokens on a separate server.
- They allow access control: Within the payload it is possible to specify user roles and permissions. You can also define the resources that the user can access.
Best Practices
- Let tokens expire: When a token is signed it will never expire unless you change the signing key or explicitly set an expiration. This could pose potential issues so it is necessary to have a strategy for expiring and/or revoking tokens.
- Do not store sensitive data in the payload: Tokens can be easily decoded, their goal is to protect against manipulation with their signature. So only add the necessary number of claims to the payload to have the best possible performance and security.
- Be a good magician, do not reveal your secret: Only reveal the signing key to services that really need it. It should be treated like any other credentials.
- Utilize HTTPS: On non-HTTPS connections the requests can be intercepted and tokens compromised more easily.
Keep in touch
Contact me through my social media. Let's talk about security, authentication and programming in general, be it on LinkedIn or GitHub.
Share with us what JWT good practices you advocate for.
Top comments (13)
I have used jwt before in cookies for front-end auth. Do you think it's a good idea to do that?
I think cookies are meant for long-lived tokens and JWTs are not meant to be long-lived.
The way in which I do it I create a JWT and a refresh token. The JWTs lasts for at most 30 minutes in my case and the refresh token which can just be any random string I normally do a UUID for that token and it can last up to a year but can only be used once. I personally just choose to store them in local storage but if I wanted to use a cookie I would only store the refresh token in an HTTP cookie that way it can not be accessed by JS.
You explained in a great and clear manner! Just adding to what you said to help Tushar in case he is unfamiliar with refresh tokens:
It's good to set a low expiration for the JWT, as low as possible. So if we set a low expiration we'll have to login into a page more often, for the user this may get annoying.
Refresh tokens were created with many purposes in mind, one of them is to enhance user experience, since it has a long expiration date and is used to generate a new JWT (in this context the JWT is called access token) when it inevitably expires with its short expiration. This avoids making us have to login into a page again when the access token expires.
There are other important purposes to them, here are useful reference material:
Thank you, for the explanation and further information, all the people answering my questions are awesome!
If using refresh tokens, when would you refresh it? Would your application have a timer that lasts the duration of the JWT and automatically uses the refresh token when the timer reaches zero, or would you keep using the JWT until an error comes back then use the refresh token? Thanks.
That is a great question. We keep using the access token (the name our JWT has when we are also dealing with refresh tokens) until it expires. Afterwards we use the refresh token with an authentication service to generate another access token (JWT) so your second assumption is correct.
How does it know that our JWT expired? In the payload we include the iat (issued at) claim with a value that is the date and time of when it was generated. Afterwards this IAT claim is compared with the exp (expiration) claim to determine if it should be accepted. If it is rejected what I wrote above happens.
Garret's comment is a useful tip. Another good thing to keep in mind is that a truly 100% secure place does not exist, so it's important to understand the limitations and unique vulnerabilities of local storage vs cookies and learn how to mitigate these vulnerabilities.
I recommend you to read the reference resources below, especially the 'So, What’s the difference?' section on the first link.
Here are useful reference resources:
Thank you, for the explanation and further information, all the people answering my questions are awesome!
Does JWT changes after each login or it is constant for a user?
It changes after each login.
To be more specific: we use the same JWT until it expires, after it expires we need to login again, after we login once more a new JWT is generated.
Thanks a lot, I have been using jwt and managing to save it to local storage or cookies and tried to find answer 'is jet constant and finally found'
Thanks 🎉
I'm happy I could help. By the way I enjoyed some of your articles, keep up the good work!
Thanks🤗.