Traditional authentication strategy makes use of sessions and cookies, but scaling these solutions is very difficult — as some kind of state is maintained by the server. JWT, on the other hand, provides a stateless solution for authentication, and stateless applications are pretty easy to scale.
Advantages of JWT
Provides a stateless authentication solution
Very popular and used by many OAuth service providers, like Google and Facebook
It’s very easy to verify a JWT token
More trustworthy than cookies and sessions
Authentication can be outsourced, or an authentication service can be used
Have many applications other than authentication — for instance, it can be used for claims
JWT structure and overview
The JWT authentication mechanism
Using JWT authentication with Node.js
JWT is used for authentication, and they can also be used for sharing information. Most JWT are signed using a public key and a private key; therefore, it’s very difficult to tamper with these tokens. JWT has three parts: head, body and signature, each separated by
The head is a
base64Url-encoded, stringified JS object that contains information about the token. The head contains the type of token, the content type of the token, and an algorithm used to sign that token. The type is specified by the field type and the algorithm used to sign the token.
The object is then converted to a string and encoded to
The following code shows how to change the encoding using the buffer module in Node.js.
Base64URL are the same; however,
+ is converted to
/ is converted to
This is done to ensure there’s no collision between the query string and the token since
+ has a special meaning in the query string (the same goes for
The body is the as the head, but it contains the claim or data that’s transferred.
The body may contain special attributes like
jti, etc. These attributes have a standard implementation and are accepted by most OAuth services. Some interesting ones are
exp specifies the time after which the token will become invalid, and
iat specifies the time when the token was created.
The time is used in seconds, following the 1 January 1970 format. The body is also converted to
Base64URL using the same code as used in the head.
This is the most important part of the token because it’s used to verify if the token is valid and authentic. Let’s see how the signature is created.
The token consists of the body and the head encrypted using any hashing algorithm — for example, SHA-256.
The algorithm can be symmetrical or asymmetrical. It depends upon the needs of the application. The example below shows how we can create a signature for JWT.
First, we create a stream from
crypto.createHmac. We push the
base64url-encoded head and body (separated by
“.”) to the created stream. Then, we convert the buffer to the
base64-encoded string and then to the
When the server verifies the token, it creates the
hash using the private key. If the
hash matches the signature on the token, then the token is authentic.
If the token is tempered with, the
hash of the token should change. But the hacker can’t create the new
hash because the key is saved with the server. Therefore, the token is verified, and the client can also be verified using the data in the body.
How Does Authentication With JWT Work?
The token with
user_id is given to the client, and the client sends the token back to the server every time the client makes an HTTP request to the server.
The client must store the token in the browser. The token can be saved in local storage or session storage. Using local storage will keep the user signed in until the token expires, and session storage will keep the user logged in until the browser tab is closed. The token is sent to the server in the authorization header as
Using JWT With Node.js
If you don't want to write your own custom JWT solution, you can always use an npm module for it. We’d first install Express and the JSON Web Tokens library.
The directory structure of the project:
key.js contains the private key, but it’s not a good practice. You should always use an
.env variable for such sensitive data.
The user schema consists of a presave hook. When we create a new user, the password is converted to
salt using bcryptjs. A static method is also added to the schema for comparing passwords using
Passwords are never saved in the database. The passwords are converted to a
hash using any hashing algorithm, with the help of
salt acts as the private key for the creating the
hash. When the user provides a password for login, the password and
salt are used to create a
hash. The created
hash is then matched with the stored one. If both
hashes match, then the password is matched.
Let’s create a simple Express server.
/api/auth/signin first matches the password and then issues a token to the user. The token is sent by the user to the server every time in the request header, and the token is parsed by the
app.use middleware every time.
The middleware also adds user details to the req as
req.user . The server listens on the port
3001 .We can also write a middleware for protecting routes.
We can use different options with the JSON Web Tokens library. We can set the expiration time, subject, time of issue, etc.
JSON Web Tokens are great for authentications and very easy to use. The tutorial shows us how we can use JWT for authentication using Node.js and Express.
JWT can also be used for different purposes, which includes any type of claim. The JWT used in the tutorial are signed using a symmetrical algorithm, but you can easily use asymmetrical algorithms also. In the asymmetrical algorithm, the private key is used to sign the token, and a public key is used for verifying the tokens.