You are on page 1of 7

9/14/2017 Common Editor

JWT (JSON Web Token)


What is JWT?
The RFC 7519 (https://tools.ietf.org/html/rfc7519) defines JWT (pronounced 'jot' - as in: "please jot down the
important points...") as a very "compact claims representation format" for space constrained environments such as
HTTP authorization headers.
That is a bizarre statement to make, read or understand (but it's an RFC after all). In simple terms, it is a token based
authentication scheme.

What does that (token based authentication) mean?


It means when the client is authenticated, he/she receives a token from the server. Every subsequent requests made
by the client thereafter is expected to contain the token which will provide the identity of the user. Now remember,
this type of authentication mechanism prevailed in the past. We used to call them session id! The session id was
created by the server and used to be passed to the client. The browser stored the session id in the cookie (or we
could also have it in the form) and it was passed back to the server with each request.

So what makes JWT's special?


The session ids in the past had problems. [A] They weren't safe. [B] they were plain text (dumb). JWT's are plain text
too, but they aren't dumb. Here is what a typical JWT token looks like.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOn
RydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

The question is how is it different from a session id? If you carefully observe the token is actually delimited by a dot
(.) Thus these are 3 strings concatenated by a dot. The three strings are base64 encoded (NOT encrypted!) and
joined together.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydW
V9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

So what ...?
Well.. if you decode each of these strings, they turn out to be JSON's!! yep ... JSONs concatenated with a dot -> jot!!
sexy isn't it? :) :) . The first token (eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9) is called as a header. The second token
(eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9) is called the payload (i like to call it
the body) and the third one (TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ) is called the signature (i like to call
it footer ... its easy to remember it conceptually like that... header,body and footer... like a letter! but of course you
can't use this terminology professionally). So a JWT is actually composed of 2 JSON's viz: header and payload
followed by a signature.

The header on decoding gives us the follows:


{
"alg": "HS256",
"typ": "JWT"
}
It specifies the type of JSON (JWT) and the algorithm used to encrypt an element of the signature. In this case, the
algorithm is HMAC SHA 256 i.e. HS256 (I don't know the details of it. Need to read up on it)

The payload on decoding becomes


{
"iss": "abc"
"exp": "
"sub": "1234567890",
"name": "John Doe",

https://www.evernote.com/Home.action?_sourcePage=8E-5WkO0YkMUD9T65RG_YvRLZ-1eYO3fqfqRu0fynRL_1nukNa4gH1t86pc1S 1/7
9/14/2017 Common Editor

"admin": true
}
For details on what those fields are, please visit (https://en.wikipedia.org/wiki/JSON_Web_Token#Standard_fields).
Suffice to know these are some of the "claims" that can be transferred between client and server.

What the heck is a claim?


A claim is a set of true values stated by a user and endorsed by an issuer. A example of a claim could be "I'm Pingala
and I invented the zero". This has to be backed by an issuer though. Technical definition of the claim can be found
here: https://msdn.microsoft.com/en-us/library/ff359101.aspx

"A claim is a statement that one subject makes about itself or another subject. The statement can be about a name,
identity, key, group, privilege, or capability, for example. Claims are issued by a provider, and they are given one or
more values and then packaged in security tokens that are issued by an issuer, commonly known as a security token
service (STS)"

Ok ... moving on...


ok ... so the payload can contain "registered claims", "public claims" and "private claims". Lastly, comes the signature
which is encrypted using HMAC 256 algorithm (in this case). The signature is generated using the following function:

signature = hmacSha256(encodedHeader + "." + encodedPayload, "s3cr3t")

You can very well use the algorithm of your choice to encrypt the signature. You could then sign the token using
symmetric key (shared key) or an asymmetric key (public key, private key).

so now you see that JWT has lot more intelligence built into it than a simple session id being passed back and forth.

Ok.. I get it... so all this ... for just security and authorization... right?
Yes authorization (NOT authentication! ... the authentication has to be achieved via some other means. I have
provided an example wherein I perform a simple hashed password authentication). So security and authorization,
are quite huge wins which usually employ logic/extra libraries/software at the server side etc. but there is another
big win that's not so apparent... and that's "Stateless server"

What do you mean by "stateless server"?


Traditionally, we created HttpSessions to store the "user state" for validation and used to pass a jsessionid to the
client. The client then passed the session id via a cookie or a hidden form field that the server code used to validate
the client. This design has the "state" managed by the server. Now imagine this war file is deployed on production
cluster. The problem gets complicated because the state being stored on one node is not available to other node on
the same cluster

https://www.evernote.com/Home.action?_sourcePage=8E-5WkO0YkMUD9T65RG_YvRLZ-1eYO3fqfqRu0fynRL_1nukNa4gH1t86pc1S 2/7
9/14/2017 Common Editor

Advanced servers provided a way to replicate sessions across clusters but simple ones like Tomcat (before 6.0)
didn't have this feature. Another solution was to employ "sticky sessions" at the load balancer wherein the load
balancer remembers which session resided on which node. So it could send request with session id 'A' to node A and
with session id 'B' to node B. The problem was if the node A failed, then load balancer didn't know where to send the
request with session id 'A'.

So we came up with an idea of storing the sessions in databases thereby maintaining the user state. That was a good
approach! But the round trip to DB and back caused some latency. This was further improved upon by using an in-
memory database like Redis/Memcached which each node could connect to and validate the user state. We
eliminated the latency but in doing so created a single point of failure (in-memory database). So we then came up
with distributed cache so that Memcached/Redis/Hazelcast can form a cluster where a single node failure of say
Hazelcast cluster would be managed by Hazelcast itself. The advantage was single point of failure was avoided but
we increased the hardware cost and some amount of efforts to manage it.

So all in all, there was a lot of effort to maintain a user state on the server. Now consider this: if the server was
"stateless" ie. it didn't store any of the user information but did it's job after user validation, then all the above efforts
would be greatly reduced isn't it?

Of course... so??
So now to extend that thought... what if the session information and it's validity if came from the client? That would
be a huge win given all the complications we had to go through to manage things at the server side.

ok... but how?


Enter JWT. JWT's payload can contain private claims wherein you can pass in any information that can be used at
the server to ensure the client is valid.

hmmm... but it is base64 encoded... which just needs to be decoded... so is it safe?


Sure it is! You could encrypt the whole payload with some algorithm and have the session information completely
safe. Besides, the signature contains the secret which is encrypted using HMAC256 which is a keyed hash and not a
cipher. So there is no way to decrypt it. If anyone tampers with the header or payload, the signature of token
changes.

At the server, we would simply compare the signature of the JWT from the client with hashed secret and then decide
to accept or reject the payload. If the hashed secret matched, we can rely on the payload information which gives us
the state and makes our server stateless.

hmm... ok how hard is it to implement?


Right now, I have an example using nodejs demonstrating how to use it, but I believe the Java way wouldn't be much
different. Imagine that we are supposed to validate a user (based on her credentials - email id and password). The
way to generate the JWT is as simple as importing the library and invoking the sign() function. To import the library,
you should have downloaded the library using 'yarn' or 'npm' and saved it into the package.json first. The command:
$ yarn add jwtwebtoken (or $ npm i -S jwtwebtoken) would do it. Anyways, the code snippet would be:

import jwt from 'jsonwebtoken';


...
...

and the actual code to generate the JWT token is as simple as invoking jwt.sign(Javascript object, secret_key) like
so...

schema.methods.generateJWT = function generateJWT() {


return jwt.sign(
{
email: this.email,
},
process.env.JWT_SECRET,

https://www.evernote.com/Home.action?_sourcePage=8E-5WkO0YkMUD9T65RG_YvRLZ-1eYO3fqfqRu0fynRL_1nukNa4gH1t86pc1S 3/7
9/14/2017 Common Editor
);
};

For those who are interested more, the entire server code is as follows:

1. You will have an index.js file containing an express application like so...

// import all 3rd party libraries

import express from 'express'; // import express library that enables us to write the server
import path from 'path'; // utility to combine paths on the file system to serve files
import dotenv from 'dotenv'; // library used for reading the environment variables
import mongoose from 'mongoose'; // ORM framework library
import bodyParser from 'body-parser'; // utlity that helps to convert the http-request into JSON object you want

// import a module which sets the routing the application. This is coded by me and not a third party library
import auth from './routes/auth';

dotenv.config(); // read the environment configuration

const app = express(); // instantiate the express object that will be used as a server
app.use(bodyParser.json()); // configure the server app to use the body parser

mongoose.connect(process.env.MONGODB_URL, { useMongoClient: true }); // connect to the MongoDB

app.use('/api/auth', auth); // route all the paths with '/api/auth' to the auth module

// capture all the generic requests to the application and route them to a static index page
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, 'index.html'));
});

// start the server


app.listen(9000, () => console.log('Server is running on localhost:9000'));

2. And then, we define a code for our model - User Object (User.js) which provides the mapping details so that
mongoose can turn that Javascript object into an ORM object like so:

import mongoose from 'mongoose'; // import ORM library


import bcrypt from 'bcrypt'; // import encryption library. One way hash
import jwt from 'jsonwebtoken'; // import JSON web token library

// TODO: add uniqueness and email validation to email fields

// define a new schema defined by this structure (dont confuse the word schema with Oracle schema
// Schema in this sense means the layout of the object... not the db concept)
const schema = new mongoose.Schema(
{
email: {
type: String,
required: true,
lowercase: true,
index: true,
},
passwordHash: { type: String, required: true },

https://www.evernote.com/Home.action?_sourcePage=8E-5WkO0YkMUD9T65RG_YvRLZ-1eYO3fqfqRu0fynRL_1nukNa4gH1t86pc1S 4/7
9/14/2017 Common Editor
},
{ timestamps: true },
);

// define isValidPassword method which compares the hashed password in DB with


// newly hashed password from user input.
schema.methods.isValidPassword = function isValidPassword(password) {
return bcrypt.compareSync(password, this.passwordHash);
};

// define the generateJWT method on the User object


schema.methods.generateJWT = function generateJWT() {
// the first part of the object are all the public claims that you want the user to see. This
// intentional
return jwt.sign(
{
email: this.email,
},
process.env.JWT_SECRET, // access the secret from the environment variable
);
};

// define the method toAuthJSON that will convert the User object into a JSON
schema.methods.toAuthJSON = function toAuthJSON() {
return {
email: this.email,
token: this.generateJWT(),
};
};

// export the schema as a User object.


export default mongoose.model('User', schema);

3. And finally, we have the express router auth.js like so:


import express from 'express'; // import the express library
import User from '../models/User'; // import the User model object defined by us User.js

const router = express.Router(); // create a router

// handle the post request on the root path


router.post('/', (req, res) => {

// read the credentials from the request. This is is a JSON object converted by the body-parser library
const { credentials } = req.body;

// invoke the ORM method provided by Mongoose


User.findOne({ email: credentials.email }) // search for the user whose email is = credentials.email
.then(user => {
// if the user is valid, invoke the checkPassword method on User object
if (user && user.isValidPassword(credentials.password)) {
// if so, send the response with user object in it
res.json({ user: user.toAuthJSON() });
} else {
res.status(400).json({ errors: { global: 'You have entered invalid credentials' } });
}
});
https://www.evernote.com/Home.action?_sourcePage=8E-5WkO0YkMUD9T65RG_YvRLZ-1eYO3fqfqRu0fynRL_1nukNa4gH1t86pc1S 5/7
9/14/2017 Common Editor
});

export default router; // expose the router to the index page where it can be imported

The entire node application has the following project structure:


.
index.html
index.js
models
User.js
routes
auth.js

The index.html looks as follows:


<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>It works!</title>
</head>
<body>
<p>
This is API not a website.
</p>
</body>
</html>

And finally the .env file stored under the root of the project has the following contents:

JWT_SECRET=s3cr3t
MONGODB_URL=mongodb://localhost/testDB

On running the application, you can see the object returned by the server with the public information (user object)
and the JWT token

https://www.evernote.com/Home.action?_sourcePage=8E-5WkO0YkMUD9T65RG_YvRLZ-1eYO3fqfqRu0fynRL_1nukNa4gH1t86pc1S 6/7
9/14/2017 Common Editor

Questions ?? :)

https://www.evernote.com/Home.action?_sourcePage=8E-5WkO0YkMUD9T65RG_YvRLZ-1eYO3fqfqRu0fynRL_1nukNa4gH1t86pc1S 7/7

You might also like