DEV Community

Rajesh T
Rajesh T

Posted on

Token based Authentication in ExpressJS Application

HTTP is a stateless protocol. That means ,it cannot maintain state of previous requests. A web application can contain some un-protected routes and some protected routes. The Un-protected routes can be accessed by any user. But protected routes can be accessed only by Authorized users.
A user can prove his authorization by submitting his credentials (username and password) for every request he makes which is practically panic. Once the server receives the user credentials, It should check with “user data” in database for correctness of user credentials. This is another nightmare which can degrade the application’s efficiency.
To overcome this problem, the concept of authentication is introduced. It works like below.

  1. When the user submits his credentials ,then the server will verify them.
    a. If username is not matched,Then it will send “invalid username” to client
    b. If password is not matched,then it will send “invalid password” to client

  2. If username and password are matched, then the server has to create either SessionID or JWT token with respect to that user and can send it as response.

(Note: You can find difference between Session based authentication and Token based authentication at
https://medium.com/@sherryhsu/session-vs-token-based-authentication-11a6c5ac45e4 )
Here ,we are using Token based authentication.

Json web token(JWT)

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between 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 the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

JSON Web Tokens are useful for:
Authorization
Information Exchange

JSON Web Token structure

JSON Web Tokens consist of three parts separated by dots (.), which are:
• Header
• Payload
• Signature

Therefore, a JWT typically looks like the following.
xxxxx.yyyyy.zzzzz

Header

The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.
For example:

{
"alg": "HS256",
"typ": "JWT"
}

Then, this JSON is Base64Url encoded to form the first part of the JWT.

Payload

The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional data
Ex:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}

The payload is then Base64Url encoded to form the second part of the JSON Web Token.

Do note that for signed tokens this information, though protected against tampering, is readable by anyone. Do not put secret information in the payload or header elements of a JWT unless it is encrypted

Signature

To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}

In authentication, when the user successfully logs in using their credentials, a JSON Web Token will be returned. Since tokens are credentials, great care must be taken to prevent security issues. In general, you should not keep tokens longer than required.

jsonwebtoken module

To create JWT token, we can use a module “jsonwebtoken”.
It has a method to encode token.
sign(payload ,secret ,callback);
We can add time duration to the token using “expiresIn” property.
Eg: 60, "2 days", "10h", "7d". A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default ("120" is equal to "120ms")
Algorithm is HS256 by default.

Let us consider the following Request handler which implements the above discussion.

const exp = require("express");
const userRouter = exp.Router();
const jwt = require("jsonwebtoken");

userRouter.post("/login", (req, res, next) => {
//get usercollection object from "req.app.locals" object
let userCollectionObj = req.app.locals.userCollectionObj;

//compare username
userCollectionObj.findOne({ username: req.body.username }, (err, userObj) => {
if (err) {
next(err);
}
//if user obj is null,then send "invalid username" to client
if (userObj == null) {
res.send({ message: "invalid username" });
}
//if user obj is not null,compare passwords
else {
bcrypt.compare(req.body.password, userObj.password, (err, isMatched) => {
if (err) {
next(err);
}
//if passwords are not matched
if (isMatched == false) {
res.send({ message: "invalid password" });
}
//if passwords are matched
else {
//create a JWT token and send it as response to client
jwt.sign(
{ username: userObj.username },
"abcdef",
{ expiresIn: 120 },
(err, signedToken) => {
if (err) {
next(err);
}
res.send({
message: "user logged in successfully",
token: signedToken,
});
}
);
}
});
}
});
});

Top comments (0)