JSON WEB TOKEN(JWT)
BY:
MUHAMMAD RASHID MUKHTAR
CONTENTS
1. Introduction
2. Cookie Based Authentication
3. Token Based Authentication
4. JSON Web Token
5. When to use JWT?
6. JWT Structure
7. How JWT works?
8. JWT v/s other methods
9. Cons
10. Server Side Application
11. Client Side Application
INTRODUCTION
1. Authentication
2. Ways to authenticate
(i). Cookie based (Stateful Authentication)
(ii). Token based (Stateless Authentication)
Cookie Based Authentication
Stateful : An authentication record or session must
be maintained. The server needs to keep track of
active sessions in a database.
Every request is accompanied by a cookie.
Whenever the user makes a request, the server
validates the cookie and session Id.
Basic flow using cookie authentication:
Procedure
User enters their login credentials.
Server verifies the credentials are correct and creates
a session which is then stored in a database.
A cookie with the session ID is placed in the users
browser.
On further requests, the session ID is verified against
the database and if valid, the request processed.
Once a user logs out of the app, the session is
destroyed both client and server side.
Features
Stateful
Coupling with web framework
Cross Origin Request Sharing(CORS)
No data storage
Performance
Token Based Authentication
Stateless: The server does not keep a record of which
users are logged in . Instead, every request to the
server is accompanied by a token which the server
uses to verify the authenticity of the request.
Basic Flow of token based authentication:
Procedure
User enters their login credentials.
Server verifies the credentials are correct and returns a
signed token.
This token is stored client-side, most commonly in local
storage.
Subsequent requests to the server include this token as
an additional Authorization header.
The server decodes the JWT and if the token is valid
processes the request
Once a user logs out, the token is destroyed client-side.
Features
Stateless
CORS / Cross-Domain
Data Storage
Performance
Compact and Self Contained
Easy implementation on Mobile
Hence, Token based authentication is better than
Cookie based authentication.
JSON Web Tokens
JSON Web Token (JWT) is a compact, open standard means of
representing claims to be transferred between two parties. These are
encoded as a JSON object that is used as the payload of a JSON Web
Signature (JWS) structure or as the plain text of a JSON Web Encryption
(JWE) structure, enabling the claims to be digitally signed.
In layman’s language, JSON Web Token(JWT) is a self-verified
encoded string that is used in Modern Web/Mobile app for both
Authentication and Authorization. The fact that it is stateless removes the
maintenance efforts that we need for other Authentication and
Authorization tools. It is used as a replacement to cookies, or rather
improvement over cookies.
Compact and Self Contained.
Used by Node.js, Ruby, python etc.
When to use JWT?
Authentication : Once the user is logged in, each
subsequent request will include the JWT, allowing the
user to access routes, services, and resources that are
permitted with that token. It’s a feature that widely
because of its small overhead and its ability to be easily
used across different domains.
Information Exchange: JSON Web Tokens are a
good way of securely transmitting information between
parties, because as they can be signed, for example using
public/private key pairs, you can be sure that the senders
are who they say they are. You can also verify that the
content hasn't been tampered. (using header and
payload)
JWT Structure
JWT Tokens consists of three parts appended by a
(dot).
➢ Header: type of token, hash algorithm
➢ Payload: claims (public, private and reserved)
➢ Signature
HEADER
PAYLOAD
Common claims are:
Issuer (iss)
Subject (sub)
Audience (aud)
Expiration time (exp)
Not before (nbf)
Issued at (iat)
JWT ID (jti)
SIGNATURE
OUTPUT (JWT)
Simple Mechanism
In JWT, a token is encoded from a data payload
using a secret.
That token is passed to the client.
Whenever the client sends that token along with a
request, the server validates it and sends back the
response.
JWT Mechanism
Step by Step Process
A client sends username/password combination to the server
The server validates the authentication
If authentication is successful, the server creates a JWT token
else establishes an error response
On successful authentication, the client gets JWT token in the
response body
Client stores that token in local storage or session storage.
From next time, the client for making any request supplies the
JWT token in request headers like this. Authorization: Bearer
<jwt_token>
Server upon receiving the JWT validates it and sends the
successful response else error.
How JWT works?
JWT v/s Other Token Methods
Better than Simple Web Token(SWT) and
SAML(Simple Assertion Markup Language).
Less verbose.
Security
Common parser
Cons of JWT
➢ Data Overhead.
➢ Security of whole platform will be compromised if the
secret key is leaked.
jsonwebtoken
There are many libraries available in different
languages developed already.
You plug them, and you get two main functionalities
to generating JWT, validate JWT, etc.
Here we pick an NPM library
called jsonwebtoken which is suggested by the
JWT website.
Install it globally or for specific project
Npm install jsonwebtoken –g//for global
Server Side Sample Application
We need to create two files other than app.js in our
application at same level.
Config.js
Middleware.js
In config.js, we just define the secret which is master
password.
This secret will be read by JWT library while creating and
validating tokens.
In production, we need to store this secret in
environment variable instead of a file.
module.exports = {
secret: ‘bcs6csp19’
};
Middleware.js
let jwt = require('jsonwebtoken');
const config = require('./config.js'); else {
req.decoded = decoded;
next();
let checkToken = (req, res, next) => {
}
let token = req.headers['x-access-token'] || });
req.headers['authorization’]; } else {
// Express headers are auto converted to lowercase return res.json({
if (token.startsWith('Bearer ')) { success: false,
// Remove Bearer from string message: 'Auth token is not supplied'
});
token = token.slice(7, token.length);
}
} };
if (token) { module.exports = {
jwt.verify(token, config.secret, (err, decoded) => { checkToken: checkToken
}
if (err) {
return res.json({
success: false,
message: 'Token is not valid'
});
}
Middleware.js
In the middleware.js, we can write a function that acts as
middleware to get a token from a request and proceeds
only when the token is validated.
In Last Code
Capture headers with names ‘x-access-token’ or ‘Authorization.’
If the header is in ‘Authorization: Bearer xxxx…’ format, strip
unwanted prefix before token.
Using jwt package and secret string, validate the token.
If anything goes wrong, return an error immediately before passing
control to next handler.
Export the middleware function for other modules to use.
At this moment, we haven’t written any code to create a
token. We will do that next.
App.js
const express = require('express'); // return the JWT token for the future API
const bodyParser = require('body- calls
parser'); res.json({
let jwt = require('jsonwebtoken'); success: true,
let config = require('./config'); message: 'Authentication successful!',
let middleware = require('./middleware'); token: token
class HandlerGenerator { });
login (req, res) { }
let username = req.body.username; else {
let password = req.body.password; res.send(403).json({
let mockedUsername = 'admin'; success: false,
let mockedPassword = 'password'; message: 'Incorrect username or
if (username && password) { password'
if (username === mockedUsername });
&& password === mockedPassword) {
let token = jwt.sign({username: } }
username}, else {
config.secret, res.send(400).json({
{ expiresIn: '24h’ success: false,
// expires in 24 hours message: 'Authentication failed! Please
} ); check the request'
});
} }
App.js
index (req, res) {
res.json({ success: true, message: 'Index page'
}); }}
// Starting point of the server
function main () {
let app = express(); // Export app for other routes to use
let handlers = new HandlerGenerator();
const port = process.env.PORT || 8000;
app.use(bodyParser.urlencoded({ // Middleware
extended: true
}));
app.use(bodyParser.json());
// Routes & Handlers
app.post('/login', handlers.login);//login request by client
app.get('/', middleware.checkToken, handlers.index);//get info after checking
app.listen(port, () => console.log(`Server is listening on port: ${port}`));
}
main();
Client Side Implementation
IN ANGULAR
34 Signup, Login & Logout
Adding Signin Component
35
Login.component.html Creating a login form
<h2 class="page-header">Login </h2>
<form (submit)="onLoginSubmit()">
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" [(ngModel)]="username" name="username">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" [(ngModel)]="password" name="password">
</div>
<input type="submit" class="btn btn-primary" value="Login">
</form>
Username, password values
2-way databinding
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';
Login.component.ts
import { Router } from '@angular/router';
import { FlashMessagesService } from 'angular2-flash-messages';
36
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
username: string;
password: string;
constructor(
private authService: AuthService,
private router: Router,
private flashMessage: FlashMessagesService
){}
ngOnInit() {
}
onLoginSubmit(){
const user = {
username: this.username,
password: this.password
}
this.authService.authenticateUser(user).subscribe(data => {
console.log(data);
});
}
}
Creating Service
37
auth.service.ts
registerUser(user){
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('http://localhost:8000/users/register', user, {headers: headers})
.map(res => res.json());
}
authenticateUser(username,password){
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('http://localhost:8000/login', username,password, {headers:
headers})
.map(res => res.json());
}
38
authenticateUser function
39
Writing authenticateUser function in Login.component.ts
file
this.authService.authenticateUser(user).subscribe(data => {
if(data.success) {
this.authService.storeUserData(data.token, data.user);
this.flashMessage.show('You are now logged in',
{cssClass: 'alert-success', timeout: 5000});
this.router.navigate(['dashboard']);
} else {
this.flashMessage.show(data.msg, {cssClass: 'alert-danger', timeout: 5000});
this.router.navigate(['login']);
}
});
Upon successful login
- Store tokens and user data in local storage (create storeUserData function in auth.service.ts)
- display login success flashMessage
- Redirect to dashboard page
When login fails
- login failed display flashMessage
- Redirect to login page
storeUserData function
40
Auth.service.ts and storeUserData
authenticateUser(user){
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('http://localhost:3000/users/authenticate',
user, {headers: headers})
.map(res => res.json());
}
storeUserData(token, user){
localStorage.setItem('id_token', token); Localstorage saved as string
localStorage.setItem('user', JSON.stringify(user));
this.authToken = token;
this.user = user;
}
Dashboard
41
Upon Successful Login Dashboard
Stored token and user information in localStorage
Logout
42
Auth.service.ts and logout function
storeUserData(token, user){
localStorage.setItem('id_token', token);
localStorage.setItem('user', JSON.stringify(user));
this.authToken = token;
this.user = user;
}
logout(){
this.authToken = null;
this.user = null; Clear the value of the login variable
localStorage.clear(); Empty local storage
}
Logout HTML
43
Logout
Navbar.component.html
<ul class="nav navbar-nav navbar-right">
<li [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}"><a
[routerLinkActive]="['active']" [routerLink]="['/login']">Login</a></li>
<li [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}"><a
[routerLinkActive]="['active']" [routerLink]="['/register']">Register</a></li>
<li><a (click)="onLogoutClick()" href="#">Logout</a></li>
</ul>
Add Logout button to menu
Clicking onLogoutClick () will be executed
onLogoutClick () function in Navbar.component.ts
Logout Feature
44
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';
import { FlashMessagesService } from 'angular2-flash-messages';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
constructor(
private authService: AuthService,
private router: Router,
private flashMessage: FlashMessagesService
){}
ngOnInit() {
}
onLogoutClick(){
this.authService.logout();
this.flashMessage.show('You are logged out', {
cssClass: 'alert-success',
timeout: 3000
});
this.router.navigate(['/login']);
return false;
}
}
45 Protected Requests & Auth Guard
Protected Request
46
▪ Token authentication for page requests
▪ Set up accessible pages only by presenting tokens while
logged in
▪ The Dashboard page is only accessible when logged in
▪ The Profile page requires a token to be presented (token
validation on the server)
▪ Server-side http: // localhost: 3000 / users / profile page
already has token authentication enabled
▪ How do I set it up?
Setting up the token authentication service
47
Add the token authentication service to the getProfile () function
in the Auth.service.ts file.
getProfile(){
let headers = new Headers();
this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type', 'application/json');
return this.http.get('http://localhost:3000/users/profile', {headers: headers})
.map(res => res.json());
}
storeUserData(token, user){
localStorage.setItem('id_token', token);
localStorage.setItem('user', JSON.stringify(user));
this.authToken = token;
this.user = user;
}
loadToken(){
const token = localStorage.getItem('id_token');
this.authToken = token;
}
profile.component.ts
48
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: Object;
constructor(
private authService: AuthService,
private router: Router
){}
ngOnInit() {
this.authService.getProfile().subscribe(profile => {
this.user = profile.user;
},
err => {
console.log(err);
return false;
});
}
}
Profile
49
Profile.component.html
Display user information only when logged in
Create div area only if user information user exists
<div *ngIf="user">
<h2 class="page-header">{{user.name}}</h2>
<ul class="list-group">
<li class="list-group-item">Username: {{user.username}}</li>
<li class="list-group-item">Email: {{user.email}}</li>
</ul>
</div>
Thank you!