Knowledge Prerequisites
JWT is widely supported with implementations on many different environments and technologies however, fundamental knowledge of JavaScript and networking is assumed in this article.
What is JWT
JWT are JSON Web Tokens. These tokens are bits of information that is tamper-proof, which allows you to use them for authenticating users. The information you store can be guarenteed to be not manipulated by the client, therefore when you receive the token back from the client, it can be safely assumed the data hasn't been changed.
For example, the server can generate a token for the user when logging in and this token can be sent to the client to be stored locally. Whenever the client wants to make an authenticated API request to the server, the client can send the token with the request so the server can identify the user making the request.
JWTs is composed of 3 parts:
- The header consisting algorithm details
- The payload containing your JSON data.
- The signature.
A token may look like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Each part is separated by a .
character and is base64 encoded.
The first part: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
is the header and when decoded to a pure string, you'll find the following JSON:
{
"alg": "HS256",
"typ": "JWT"
}
This tells us this token is using the HS256
encryption algorithm and that the type is a JWT
type.
The next part is the payload: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
will produce the following JSON:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
This is the application data, however there are a few keys that are filled by many JWT implementations such as the iat
(Issue At) timestamp and the sub
(subject). Most of the JWT provided fields are optional, but it's important to know about them to avoid name collisions.
If they are secure, why can we decrypt them?
Good question! JWT simply ensures that that the generated token hasn't been tampered with. So that a token that is generated by the server can be trusted to be the same contents when it receives that token from the client. It does not encrypt the contents of the payload, so anybody that gains access to the token can still read the data!
The last part is the signature: SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
If you tried to base64 decode this string, you would have ended up with binary jibberish. That's because this is part of a one-way encrypted hash which ensures that the rest of the token hasn't been manipulated when verified by the server with the proper secret.
Visit JWT.io to play with JWT tokens and generations in your browser.
Security
Using JWTs is safe for security applications, however there are a few things to keep in mind. JWT is a open industry standard RFC 7519 for communicating between two parties securely.
If there is still concerns about it's concept, maybe it will help to know that Auth0* makes heavy use of JWT for their business.
When choosing an implementation, I suggest using the JWT.io website for their library list of implementations.
* I have no affilation with Auth0.
It's important to choose a trusted library that is secure.
Needless to say, security doesn't stop at the implementation. For JWTs to be secure, they must be signed with a strong secret. If a secret would ever be leaked or exposed, then anybody could generate tokens that the server deems valid. Additionally the generated tokens should be given to the intended clients only.
JWT tokens are not meant to store sensitive information. They are simply a means to ensure that a message hasn't been tampered with.
This means you can also securely verify a user without making a trip to the database.
Token Lifetime
The example token used earlier had an Issue At (iat
) field which contained a timestamp in epoch time. This let us know when the token was created, however this token did not have an expiration date.
This isn't very desirable as this means once a token is generated, it is accepted by the server forever.
A token should be created with an expiration date. When should the token expire? That depends on your use case, but short-lived tokens paired with long one-time used renew tokens is recommended.
The idea is the access token is short lived and only usable for 10-15 minutes before they expire. Once the access token is expired, the client can use the renew token to obtain a new access token. The renew token is a long lived token that can last hours or days, depending on the application requirements.
As discussed above, JWTs can be easily read by anybody who obtains access. This means care should be taken when choosing what to store in the token. Some good candidates are:
- Unique user identifier that doesn't invade privacy such as a unique hash.
- Some settings, that is used to control visible UI elements, such as user roles.
Some bad candidates are:
- User names or passwords
- Personally identifiable information such as names or emails
- Sensitive information like medical or banking details
Additionally, these tokens are generally stored in cookies or in an HTTP header and are passed to the server on any authenticated request. Sometimes there are limits to how large the token is, so it's desirable to keep token payload as small as possible. Only include just enough information to identify the user. Afterall, an API can always fulfil the ability to get up-to-date profile details about that user.
To conclude
JSON Web Tokens is an excellent way to efficiently and securely authenticate and identify users when used properly. Personally I use the NodeJS jsonwebtoken module in my projects, developed by Auth0. There is also a @types/jsonwebtoken package for TypeScript users.
About the author
Norman Breau is an IT professional with over 10 years of field experience.
He has a wide range of skill sets, ranging from web & software development &
architecture, to Server & Database administration. Presently he works at
TotalPave where he plays
a lead role in software projects as well as manages the server infrastructure.
On his own time, he volunteers to some open source projects, namely Apache Cordova, as many projects
throughout his career were dependent on the Cordova project. Open source projects works the best when there are volunteers that depend on such software is able to contribute in some form.
Additionally, he has been working on a newer project called Fuse,
a framework for building native-web hybrid mobile applications. The framework
intends to fill a void somewheres between CapacitorJS and pure native development.
Fuse is simply just a native library, with a bundleable webview JS API.
Unlike Cordova and CapacitorJS, Fuse is more tailored to native developers,
who want to still utilise the webview for their application's UI but retain
full control over the native project and native code. The only requirement
is that Fuse needs to be installed in the application along with a compatible
Fuse JS runtime. Fuse offers the webview and a bridging API that natively
supports binary and is incredibly fast.
Like all websites, web hosting costs money. If the above article has helped you, please considering offering a small tip as a token of appreciation.