Академический Документы
Профессиональный Документы
Культура Документы
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.
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.
"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)"
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"
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.
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.
and the actual code to generate the JWT token is as simple as invoking jwt.sign(Javascript object, secret_key) like
so...
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 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';
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
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'));
});
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:
// 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 the method toAuthJSON that will convert the User object into a JSON
schema.methods.toAuthJSON = function toAuthJSON() {
return {
email: this.email,
token: this.generateJWT(),
};
};
// read the credentials from the request. This is is a JSON object converted by the body-parser library
const { credentials } = req.body;
export default router; // expose the router to the index page where it can be imported
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