SlideShare une entreprise Scribd logo
1  sur  93
Copyright © 2016 M/Gateway Developments Ltd
EWD 3 Training Course
Part 43
Using JSON Web Tokens
with QEWD REST Services
Rob Tweed
Director, M/Gateway Developments Ltd
Twitter: @rtweed
Copyright © 2016 M/Gateway Developments Ltd
Using JSON Web Tokens with
QEWD REST Services
• This part of the course assumes that
you've taken, at least:
• Part 2: Overview of EWD 3
– https://www.slideshare.net/robtweed/ewd-3-overview
• Part 4: Installing & Configuring QEWD
– https://www.slideshare.net/robtweed/installing-configuring-ewdxpress
• Part 31: Using QEWD for Web and REST
Services
– http://www.slideshare.net/robtweed/ewd-3-training-course-part-31-ewdxpress-for-web-and-rest-services
Copyright © 2016 M/Gateway Developments Ltd
JSON Web Tokens:
Background
• For an introduction on JSON Web Tokens
(JWTs), what they are, how they work and
when and why they should be considered,
see this presentation on QEWD and
JWTs:
• https://www.slideshare.net/robtweed/qewdjs-json-web-tokens-microservices
Copyright © 2016 M/Gateway Developments Ltd
Moving to JWTs
• In this course, we'll change the example
application that was described in Part 31
– From using QEWD server-side Sessions
– To using browser-side JWTs
Copyright © 2016 M/Gateway Developments Ltd
Our original QEWD startup file
var config = {
managementPassword: 'keepThisSecret!',
serverName: 'QEWD REST Server',
port: 8080,
poolSize: 2,
database: {
type: 'gtm'
}
};
var routes = [
{path: '/api', module: 'myRestService'}
];
var qewd = require('qewd').master;
qewd.start(config, routes);
~/qewd/rest.js
Copyright © 2016 M/Gateway Developments Ltd
Tell QEWD to enable JWTs
var config = {
managementPassword: 'keepThisSecret!',
serverName: 'QEWD REST Server',
port: 8080,
poolSize: 2,
database: {
type: 'gtm'
},
jwt: {
secret: 'someSecret123'
}
};
var routes = [
{path: '/api', module: 'myRestService'}
];
var qewd = require('qewd').master;
qewd.start(config, routes);
The secret can be any
text string you want.
The longer and less
guessable the better
Copyright © 2016 M/Gateway Developments Ltd
Modify the Worker Process
Handler Module
• Instead of standard server-side QEWD
Sessions:
– /api/login should create a new JWT
• Send it as the token response just as before
Copyright © 2016 M/Gateway Developments Ltd
Modify the Worker Process
Handler Module
• Instead of standard server-side QEWD
Sessions:
– /api/login should create a new JWT
• Send it as the token response just as before
– All other routes should include the JWT in the
Authorization Header
• Authorization: Bearer {{JWT}}
Copyright © 2016 M/Gateway Developments Ltd
Modify the Worker Process
Handler Module
• Instead of standard server-side QEWD
Sessions:
– /api/login should create a new JWT
• Send it as the token response just as before
– All other routes should include the JWT in the
Authorization Header
• Authorization: Bearer {{JWT}}
– Validate the incoming JWT and use its
payload to get/set session values
Copyright © 2016 M/Gateway Developments Ltd
Edit the handler module
• ~/qewd/node_modules/myRestService.js
• All we need to do is:
– Modify the login() function
– Modify the beforeHandler() function
Copyright © 2016 M/Gateway Developments Ltd
Modify the Worker Process
Handler Module
• Instead of standard server-side QEWD
Sessions:
– /api/login should create a new JWT
• Send it as the token response just as before
– All other routes should include the JWT in the
Authorization Header
• Authorization: Bearer {{JWT}}
– Validate the incoming JWT and use its
payload to get/set session values
Copyright © 2016 M/Gateway Developments Ltd
Original Login Function
function login(args, finished) {
var username = args.req.body.username;
if (!username || username === '') {
return finished({error: 'You must provide a username'});
}
var password = args.req.body.password;
if (!password || password === '') {
return finished({error: 'You must provide a password'});
}
if (username !== 'rob') return finished({error: 'Invalid username'});
if (password !== 'secret') return finished({error: 'Invalid password'});
var session = this.sessions.create('testWebService', 3600);
session.authenticated = true;
session.data.$('username').value = username;
finished({token: session.token});
}
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTs
function login(args, finished) {
var username = args.req.body.username;
if (!username || username === '') {
return finished({error: 'You must provide a username'});
}
var password = args.req.body.password;
if (!password || password === '') {
return finished({error: 'You must provide a password'});
}
if (username !== 'rob') return finished({error: 'Invalid username'});
if (password !== 'secret') return finished({error: 'Invalid password'});
var session = this.jwt.handlers.createRestSession.call(this, args);
session.welcomeText = 'Welcome ' + username;
session.username = username;
session.authenticated = true;
session.timeout = 1200;
var jwt = this.jwt.handlers.setJWT.call(this, session);
finished({token: jwt});
}
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTs
function login(args, finished) {
var username = args.req.body.username;
if (!username || username === '') {
return finished({error: 'You must provide a username'});
}
var password = args.req.body.password;
if (!password || password === '') {
return finished({error: 'You must provide a password'});
}
if (username !== 'rob') return finished({error: 'Invalid username'});
if (password !== 'secret') return finished({error: 'Invalid password'});
var session = this.jwt.handlers.createRestSession.call(this, args);
session.welcomeText = 'Welcome ' + username;
session.username = username;
session.authenticated = true;
session.timeout = 1200;
var jwt = this.jwt.handlers.setJWT.call(this, session);
finished({token: jwt});
}
Create a new JWT-compatible
Session object, using
information from the request
this.jwt.handlers provides
the APIs you'll need for JWT
Handling
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTs
function login(args, finished) {
var username = args.req.body.username;
if (!username || username === '') {
return finished({error: 'You must provide a username'});
}
var password = args.req.body.password;
if (!password || password === '') {
return finished({error: 'You must provide a password'});
}
if (username !== 'rob') return finished({error: 'Invalid username'});
if (password !== 'secret') return finished({error: 'Invalid password'});
var session = this.jwt.handlers.createRestSession.call(this, args);
session.welcomeText = 'Welcome ' + username;
session.username = username;
session.authenticated = true;
session.timeout = 1200;
var jwt = this.jwt.handlers.setJWT.call(this, session);
finished({token: jwt});
}
Add some extra properties
of our own to the
Session Object
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTs
function login(args, finished) {
var username = args.req.body.username;
if (!username || username === '') {
return finished({error: 'You must provide a username'});
}
var password = args.req.body.password;
if (!password || password === '') {
return finished({error: 'You must provide a password'});
}
if (username !== 'rob') return finished({error: 'Invalid username'});
if (password !== 'secret') return finished({error: 'Invalid password'});
var session = this.jwt.handlers.createRestSession.call(this, args);
session.welcomeText = 'Welcome ' + username;
session.username = username;
session.authenticated = true;
session.timeout = 1200;
var jwt = this.jwt.handlers.setJWT.call(this, session);
finished({token: jwt});
}
The authenticated and
timeout properties are
special built-in ones
timeout specifies how
long before the JWT
expires
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTs
function login(args, finished) {
var username = args.req.body.username;
if (!username || username === '') {
return finished({error: 'You must provide a username'});
}
var password = args.req.body.password;
if (!password || password === '') {
return finished({error: 'You must provide a password'});
}
if (username !== 'rob') return finished({error: 'Invalid username'});
if (password !== 'secret') return finished({error: 'Invalid password'});
var session = this.jwt.handlers.createRestSession.call(this, args);
session.welcomeText = 'Welcome ' + username;
session.username = username;
session.authenticated = true;
session.timeout = 1200;
var jwt = this.jwt.handlers.setJWT.call(this, session);
finished({token: jwt});
}
Create a JWT from
the Session data.
The secret you defined in the
startup file is used by QEWD
to sign the JWT
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTs
function login(args, finished) {
var username = args.req.body.username;
if (!username || username === '') {
return finished({error: 'You must provide a username'});
}
var password = args.req.body.password;
if (!password || password === '') {
return finished({error: 'You must provide a password'});
}
if (username !== 'rob') return finished({error: 'Invalid username'});
if (password !== 'secret') return finished({error: 'Invalid password'});
var session = this.jwt.handlers.createRestSession.call(this, args);
session.welcomeText = 'Welcome ' + username;
session.username = username;
session.authenticated = true;
session.timeout = 1200;
var jwt = this.jwt.handlers.setJWT.call(this, session);
finished({token: jwt});
}
Finally, return the
JWT as the response
Copyright © 2016 M/Gateway Developments Ltd
Start QEWD using your startup file
cd ~/qewd
node rest
Copyright © 2016 M/Gateway Developments Ltd
Try out the /api/login Request
Copyright © 2016 M/Gateway Developments Ltd
Here's our JWT
Copyright © 2016 M/Gateway Developments Ltd
Inspecting a JWT
• Use:
– https://jwt.io/
Copyright © 2016 M/Gateway Developments Ltd
Inspecting a JWT
Copyright © 2016 M/Gateway Developments Ltd
Here's our JWT
A JWT has 3 Base64-encoded parts, separated by a "."
Copyright © 2016 M/Gateway Developments Ltd
Here's our JWT
We're only really interested in the middle bit – the payload
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
Anyone can Base64 Decode the payload of a JWT
Secret is not required for this
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
Here's the timeout we set
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
…and the other properties we set in the Session
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
These are reserved JWT payload properties
QEWD created them for you
Known as "reserved claims"
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
This was added by QEWD, using the incoming
Request payload data. It's used by QEWD
internally
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
The qewd property/claim is encrypted using the
Secret, so is only usable by anyone with access
to the Secret. It contains data for use in the QEWD
Back-end only
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
You can optionally add data into this private claim,
but only from within your worker process handler
functions: see later
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
If a client returning a JWT makes any changes to
the payload, the signature will no longer match,
so it will be rejected by QEWD
Copyright © 2016 M/Gateway Developments Ltd
Modify the Worker Process
Handler Module
• Instead of standard server-side QEWD
Sessions:
– /api/login should create a new JWT
• Send it as the token response just as before
– All other routes should include the JWT in the
Authorization Header
• Authorization: Bearer {{JWT}}
– Validate the incoming JWT and use its
payload to get/set session values
Copyright © 2016 M/Gateway Developments Ltd
Add the JWT Authorization Header
Copyright © 2016 M/Gateway Developments Ltd
Modify the Worker Process
Handler Module
• Instead of standard server-side QEWD
Sessions:
– /api/login should create a new JWT
• Send it as the token response just as before
– All other routes should include the JWT in the
Authorization Header
• Authorization: Bearer {{JWT}}
– Validate the incoming JWT and use its
payload to get/set session values
Copyright © 2016 M/Gateway Developments Ltd
Edit the handler module
• ~/qewd/node_modules/myRestService.js
• All we need to do is:
– Modify the login() function
– Modify the beforeHandler() function
Copyright © 2016 M/Gateway Developments Ltd
Here's the original
beforeHandler() function
beforeHandler: function(req, finished) {
if (req.path !== '/api/login') {
return this.sessions.authenticateRestRequest(req, finished);
}
},
Using server-side
QEWD Sessions
Copyright © 2016 M/Gateway Developments Ltd
Modified to use JWTs
beforeHandler: function(req, finished) {
if (req.path !== '/api/login') {
return this.jwt.handlers.validateRestRequest.call(this, req, finished);
}
},
Change to use this API
- Checks the JWT's signature
using the Secret
- Checks if the JWT has expired
- Unpacks the JWT payload into
the Session object
- Decrypts the qewd claim
Copyright © 2016 M/Gateway Developments Ltd
We'll try the /api/search API
• But first we need to check its handler
function:
init: function(application) {
routes = [
{
url: '/api/search',
//method: 'GET',
handler: search
},
Copyright © 2016 M/Gateway Developments Ltd
Original /api/search handler function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
finished({
test: 'finished ok',
username: args.session.data.$('username').value
});
}
Copyright © 2016 M/Gateway Developments Ltd
Original /api/search handler function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
finished({
test: 'finished ok',
username: args.session.data.$('username').value
});
}
Will display the args object
To the QEWD Node.js console
Copyright © 2016 M/Gateway Developments Ltd
Original /api/search handler function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
finished({
test: 'finished ok',
username: args.session.data.$('username').value
});
}
Returns the username from
the back-end QEWD Session
Copyright © 2016 M/Gateway Developments Ltd
Change it to use the JWT-derived Session
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
finished({
test: 'finished ok',
username: args.session.username
});
}
args.session now contains
the Session object, containing
the JWT payload
QEWD did this for us
automatically
Copyright © 2016 M/Gateway Developments Ltd
Restart QEWD and Try It
Copyright © 2016 M/Gateway Developments Ltd
Restart QEWD and Try It
Copyright © 2016 M/Gateway Developments Ltd
Take a look at the QEWD
Node.js Console Log
*** search args: {
"req": {
"type": "ewd-qoper8-express",
"path": "/api/search",
"method": "GET",
"headers": {
"host": "192.168.1.117:8080",
"authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MD…",
"content-type": "application/json"
},
"params": {
"type": "search"
},
"query": {},
"body": {},
"ip": "::ffff:192.168.1.74",
"ips": [],
"application": "api",
"expressType": "search",
…...
Here's the args object
Copyright © 2016 M/Gateway Developments Ltd
Scroll down further…
"session": {
"exp": 1503046402,
"iat": 1503045202,
"iss": "qewd.jwt",
"application": "api",
"timeout": 1200,
"qewd": {
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true
},
"welcomeText": "Welcome rob",
"username": "rob",
"qewd_list": {
"ipAddress": true,
"authenticated": true
},
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true
}
}
Here's args.session
Contains the JWT payload
values
Copyright © 2016 M/Gateway Developments Ltd
args.session
"session": {
"exp": 1503046402,
"iat": 1503045202,
"iss": "qewd.jwt",
"application": "api",
"timeout": 1200,
"qewd": {
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true
},
"welcomeText": "Welcome rob",
"username": "rob",
"qewd_list": {
"ipAddress": true,
"authenticated": true
},
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true
}
}
Here's the username
value that was added
to the JWT Session
by the login function
Copyright © 2016 M/Gateway Developments Ltd
args.session
"session": {
"exp": 1503046402,
"iat": 1503045202,
"iss": "qewd.jwt",
"application": "api",
"timeout": 1200,
"qewd": {
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true
},
"welcomeText": "Welcome rob",
"username": "rob",
"qewd_list": {
"ipAddress": true,
"authenticated": true
},
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true
}
}
But also notice the
qewd claim
It's been decrypted
Copyright © 2016 M/Gateway Developments Ltd
args.session
"session": {
"exp": 1503046402,
"iat": 1503045202,
"iss": "qewd.jwt",
"application": "api",
"timeout": 1200,
"qewd": {
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true
},
"welcomeText": "Welcome rob",
"username": "rob",
"qewd_list": {
"ipAddress": true,
"authenticated": true
},
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true
}
}
And its properties have
been copied to
args.session, as
properties in their
own right
Copyright © 2016 M/Gateway Developments Ltd
JWT-based Session
• Your handler functions can
add/change/delete properties within the
Session by accessing the args.session
properties
• Don't modify the reserved claim properties
– iss
– exp
– iat
– application
Copyright © 2016 M/Gateway Developments Ltd
JWT-based Session
• By default, any properties you add to the
Session will be visible within the JWT
payload (after Base64 decoding)
• We saw this with the username and
welcomeText fields
– Added in the login() function
– We cut and pasted the JWT into the jwt.io
Inspector screen
Copyright © 2016 M/Gateway Developments Ltd
Here's the login() function
function login(args, finished) {
var username = args.req.body.username;
if (!username || username === '') {
return finished({error: 'You must provide a username'});
}
var password = args.req.body.password;
if (!password || password === '') {
return finished({error: 'You must provide a password'});
}
if (username !== 'rob') return finished({error: 'Invalid username'});
if (password !== 'secret') return finished({error: 'Invalid password'});
var session = this.jwt.handlers.createRestSession.call(this, args);
session.welcomeText = 'Welcome ' + username;
session.username = username;
session.authenticated = true;
session.timeout = 1200;
var jwt = this.jwt.handlers.setJWT.call(this, session);
finished({token: jwt});
}
username and
welcomeText
added to the
Session Object
Copyright © 2016 M/Gateway Developments Ltd
Inspecting a JWT
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
Copyright © 2016 M/Gateway Developments Ltd
JWT-based Session
• There may be properties/values that you
want to add to the JWT/Session that are
visible and usable in your back-end
handler functions, but too sensitive to be
visible to the client/user
• QEWD makes this easy
Copyright © 2016 M/Gateway Developments Ltd
JWT-based Session
• There may be properties/values that you
want to add to the JWT/Session that are
visible and usable in your back-end
handler functions, but too sensitive to be
visible to the client/user
• QEWD makes this easy
– Let's make the username secret, but leave the
welcomeText visible
Copyright © 2016 M/Gateway Developments Ltd
Edit the login() function
function login(args, finished) {
var username = args.req.body.username;
if (!username || username === '') {
return finished({error: 'You must provide a username'});
}
var password = args.req.body.password;
if (!password || password === '') {
return finished({error: 'You must provide a password'});
}
if (username !== 'rob') return finished({error: 'Invalid username'});
if (password !== 'secret') return finished({error: 'Invalid password'});
var session = this.jwt.handlers.createRestSession.call(this, args);
session.welcomeText = 'Welcome ' + username;
session.username = username;
session.makeSecret('username');
session.authenticated = true;
session.timeout = 1200;
var jwt = this.jwt.handlers.setJWT.call(this, session);
finished({token: jwt});
}
Just add this
Copyright © 2016 M/Gateway Developments Ltd
Restart QEWD. Send /api/login
Copyright © 2016 M/Gateway Developments Ltd
Restart QEWD. Send /api/login
Copy the JWT
Copyright © 2016 M/Gateway Developments Ltd
Paste it into the jwt.io Inspector
Copyright © 2016 M/Gateway Developments Ltd
Paste it into the jwt.io Inspector
welcomeText is still visible
but username has disappeared
It's been encrypted into the qewd
claim
Copyright © 2016 M/Gateway Developments Ltd
Now send /api/search using new JWT
Copyright © 2016 M/Gateway Developments Ltd
Now send /api/search using new JWT
username appears as before
Copyright © 2016 M/Gateway Developments Ltd
Take a look at args.session in
the QEWD Node.js Console Log
"session": {
"exp": 1503049897,
"iat": 1503048697,
"iss": "qewd.jwt",
"application": "api",
"timeout": 1200,
"qewd": {
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
},
"welcomeText": "Welcome rob",
"qewd_list": {
"ipAddress": true,
"authenticated": true,
"username": true
},
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
}
Copyright © 2016 M/Gateway Developments Ltd
Take a look at args.session in
the QEWD Node.js Console Log
"session": {
"exp": 1503049897,
"iat": 1503048697,
"iss": "qewd.jwt",
"application": "api",
"timeout": 1200,
"qewd": {
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
},
"welcomeText": "Welcome rob",
"qewd_list": {
"ipAddress": true,
"authenticated": true,
"username": true
},
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
}
username is inside the
qewd sub-object
Copyright © 2016 M/Gateway Developments Ltd
Take a look at args.session in
the QEWD Node.js Console Log
"session": {
"exp": 1503049897,
"iat": 1503048697,
"iss": "qewd.jwt",
"application": "api",
"timeout": 1200,
"qewd": {
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
},
"welcomeText": "Welcome rob",
"qewd_list": {
"ipAddress": true,
"authenticated": true,
"username": true
},
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
}
And has been added as a
property in its own right to
args.session
Copyright © 2016 M/Gateway Developments Ltd
Take a look at args.session in
the QEWD Node.js Console Log
"session": {
"exp": 1503049897,
"iat": 1503048697,
"iss": "qewd.jwt",
"application": "api",
"timeout": 1200,
"qewd": {
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
},
"welcomeText": "Welcome rob",
"qewd_list": {
"ipAddress": true,
"authenticated": true,
"username": true
},
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
}
If the JWT is updated, username
remains secret. It is removed as
a property in its own right before the
JWT is created
Copyright © 2016 M/Gateway Developments Ltd
Take a look at args.session in
the QEWD Node.js Console Log
"session": {
"exp": 1503049897,
"iat": 1503048697,
"iss": "qewd.jwt",
"application": "api",
"timeout": 1200,
"qewd": {
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
},
"welcomeText": "Welcome rob",
"qewd_list": {
"ipAddress": true,
"authenticated": true,
"username": true
},
"ipAddress": "::ffff:192.168.1.74",
"authenticated": true,
"username": "rob"
}
If the JWT is updated, username
remains secret. It is removed as
a property in its own right before the
JWT is created
That's the purpose of this
QEWD-managed sub-object
Copyright © 2016 M/Gateway Developments Ltd
Modifying/Updating the JWT
• You may want to add
values/objects/arrays to the JWT-based
session within your handler functions
• If so, you need to create a new JWT using
the args.session object and return it with
the response
• It's a good idea to return an updated JWT
even if you don't add/change session data
– To update the JWT's expiry time
Copyright © 2016 M/Gateway Developments Ltd
Modifying/Updating the JWT
• Let's make the /api/search handler update
the JWT
Copyright © 2016 M/Gateway Developments Ltd
Here's our search() function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
finished({
test: 'finished ok',
username: args.session.username
});
}
Copyright © 2016 M/Gateway Developments Ltd
Edit the search() function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
args.session.ranSearchAt = Date.now();
finished({
test: 'finished ok',
username: args.session.username
});
}
Add a new property – ranSearchAt -
to args.session
Copyright © 2016 M/Gateway Developments Ltd
Edit the search() function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
args.session.ranSearchAt = Date.now();
var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({
test: 'finished ok',
username: args.session.username
});
} Create a new JWT using args.session
Copyright © 2016 M/Gateway Developments Ltd
Edit the search() function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
args.session.ranSearchAt = Date.now();
var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({
test: 'finished ok',
username: args.session.username,
token: jwt
});
}
Return the new JWT with the response
Copyright © 2016 M/Gateway Developments Ltd
Restart QEWD and send /api/search
Copyright © 2016 M/Gateway Developments Ltd
Restart QEWD and send /api/search
Here's the new JWT – let's inspect it
Copyright © 2016 M/Gateway Developments Ltd
The new JWT
Copyright © 2016 M/Gateway Developments Ltd
The new JWT
Here's the field we added
Copyright © 2016 M/Gateway Developments Ltd
Restart QEWD and send /api/search
Where is username?
Copyright © 2016 M/Gateway Developments Ltd
Look in the search() function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
args.session.ranSearchAt = Date.now();
var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({
test: 'finished ok',
username: args.session.username,
token: jwt
});
}
We're asking it to send the username
using the value in args.session.username
Copyright © 2016 M/Gateway Developments Ltd
Look in the search() function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
args.session.ranSearchAt = Date.now();
var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({
test: 'finished ok',
username: args.session.username,
token: jwt
});
}
We're asking it to send the username
using the value in args.session.username
But we're doing this after we created the
new JWT. In doing so, all secret fields
have been removed from args.session
So args.session.username no longer
exists
Copyright © 2016 M/Gateway Developments Ltd
Edit the search() function
function search(args, finished) {
console.log('*** search args: ' + JSON.stringify(args, null, 2));
args.session.ranSearchAt = Date.now();
var username = args.session.username;
var jwt = this.jwt.handlers.setJWT.call(this, args.session);
finished({
test: 'finished ok',
username: username,
token: jwt
});
} Let's get hold of the username value
before the JWT is created, and
send that value in the response
Copyright © 2016 M/Gateway Developments Ltd
Restart QEWD and Try Again
Copyright © 2016 M/Gateway Developments Ltd
Restart QEWD and Try Again
Now username appears as expected
Copyright © 2016 M/Gateway Developments Ltd
Using JWTs with QEWD REST Services
• You now know everything needed to use
JWTs with QEWD.js REST Services
• JWTs allow a very different approach to
authentication and session management
– Completely stateless architecture
– Does not require any database for session
management
– State/session info is held by client in the JWT
Copyright © 2016 M/Gateway Developments Ltd
Using JWTs with QEWD REST Services
• JWTs allow you to scale out your
QEWD.js systems
– Multiple QEWD systems just need to share
the same secret
• Each defines the same secret text string in their
QEWD startup file
Copyright © 2016 M/Gateway Developments Ltd
JWT security
Server
Client
Both servers share same secret key
Server
Copyright © 2016 M/Gateway Developments Ltd
JWT security
Server
Client
Server
Create initial JWT
Copyright © 2016 M/Gateway Developments Ltd
JWT security
Server
Client
Server
Validate and use JWT
Copyright © 2016 M/Gateway Developments Ltd
QEWD.js Architecture
ewd-qoper8
queue
Express
Node.js
socket.io
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
ewd-qoper8
queue
Express
Node.js
socket.io
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
ewd-qoper8
queue
Express
Node.js
socket.io
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Cache
GT.M,
YottaDB
Redis
Node.js
Worker
Process
Load Balancer
Or Proxy (eg nginx)
Same Secret
Copyright © 2016 M/Gateway Developments Ltd
Using JWTs with QEWD REST Services
• JWTs also provide the basis by which you
can break out your QEWD.js applications
into fine-grained MicroServices, each
running in their own separate
machine/VM/container
• This will be described in the next part of
this course.

Contenu connexe

Tendances

Tendances (20)

EWD 3 Training Course Part 11: Handling Errors in QEWD
EWD 3 Training Course Part 11: Handling Errors in QEWDEWD 3 Training Course Part 11: Handling Errors in QEWD
EWD 3 Training Course Part 11: Handling Errors in QEWD
 
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD ApplicationEWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
EWD 3 Training Course Part 5a: First Steps in Building a QEWD Application
 
QEWD.js, JSON Web Tokens & MicroServices
QEWD.js, JSON Web Tokens & MicroServicesQEWD.js, JSON Web Tokens & MicroServices
QEWD.js, JSON Web Tokens & MicroServices
 
EWD 3 Training Course Part 14: Using Ajax for QEWD Messages
EWD 3 Training Course Part 14: Using Ajax for QEWD MessagesEWD 3 Training Course Part 14: Using Ajax for QEWD Messages
EWD 3 Training Course Part 14: Using Ajax for QEWD Messages
 
EWD 3 Training Course Part 30: Modularising QEWD Applications
EWD 3 Training Course Part 30: Modularising QEWD ApplicationsEWD 3 Training Course Part 30: Modularising QEWD Applications
EWD 3 Training Course Part 30: Modularising QEWD Applications
 
EWD 3 Training Course Part 27: The QEWD Session
EWD 3 Training Course Part 27: The QEWD SessionEWD 3 Training Course Part 27: The QEWD Session
EWD 3 Training Course Part 27: The QEWD Session
 
EWD 3 Training Course Part 16: QEWD Services
EWD 3 Training Course Part 16: QEWD ServicesEWD 3 Training Course Part 16: QEWD Services
EWD 3 Training Course Part 16: QEWD Services
 
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
EWD 3 Training Course Part 37: Building a React.js application with ewd-xpres...
 
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
EWD 3 Training Course Part 38: Building a React.js application with QEWD, Part 4
 
EWD 3 Training Course Part 4: Installing & Configuring QEWD
EWD 3 Training Course Part 4: Installing & Configuring QEWDEWD 3 Training Course Part 4: Installing & Configuring QEWD
EWD 3 Training Course Part 4: Installing & Configuring QEWD
 
EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...
EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...
EWD 3 Training Course Part 13: Putting Everything so far into Practice using ...
 
EWD 3 Training Course Part 34: QEWD Resilient Mode
EWD 3 Training Course Part 34: QEWD Resilient ModeEWD 3 Training Course Part 34: QEWD Resilient Mode
EWD 3 Training Course Part 34: QEWD Resilient Mode
 
EWD 3 Training Course Part 2: EWD 3 Overview
EWD 3 Training Course Part 2: EWD 3 OverviewEWD 3 Training Course Part 2: EWD 3 Overview
EWD 3 Training Course Part 2: EWD 3 Overview
 
EWD 3 Training Course Part 12: QEWD Session Timeout Control
EWD 3 Training Course Part 12: QEWD Session Timeout ControlEWD 3 Training Course Part 12: QEWD Session Timeout Control
EWD 3 Training Course Part 12: QEWD Session Timeout Control
 
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
EWD 3 Training Course Part 39: Building a React.js application with QEWD, Part 3
 
EWD 3 Training Course Part 19: The cache.node APIs
EWD 3 Training Course Part 19: The cache.node APIsEWD 3 Training Course Part 19: The cache.node APIs
EWD 3 Training Course Part 19: The cache.node APIs
 
EWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a ServiceEWD 3 Training Course Part 29: Running QEWD as a Service
EWD 3 Training Course Part 29: Running QEWD as a Service
 
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWDEWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
EWD 3 Training Course Part 28: Integrating Legacy Mumps Code with QEWD
 
EWD 3 Training Course Part 6: What Happens when a QEWD Application is Started
EWD 3 Training Course Part 6: What Happens when a QEWD Application is StartedEWD 3 Training Course Part 6: What Happens when a QEWD Application is Started
EWD 3 Training Course Part 6: What Happens when a QEWD Application is Started
 
EWD 3 Training Course Part 20: The DocumentNode Object
EWD 3 Training Course Part 20: The DocumentNode ObjectEWD 3 Training Course Part 20: The DocumentNode Object
EWD 3 Training Course Part 20: The DocumentNode Object
 

Similaire à EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services

Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
Tom Croucher
 
Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Events
tkramar
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
Ran Mizrahi
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
Wesley Beary
 

Similaire à EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services (20)

SproutCore and the Future of Web Apps
SproutCore and the Future of Web AppsSproutCore and the Future of Web Apps
SproutCore and the Future of Web Apps
 
Join the darkside: Selenium testing with Nightwatch.js
Join the darkside: Selenium testing with Nightwatch.jsJoin the darkside: Selenium testing with Nightwatch.js
Join the darkside: Selenium testing with Nightwatch.js
 
Mashing up JavaScript
Mashing up JavaScriptMashing up JavaScript
Mashing up JavaScript
 
Mashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web AppsMashing up JavaScript – Advanced Techniques for modern Web Apps
Mashing up JavaScript – Advanced Techniques for modern Web Apps
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applications
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
DataStax: 0 to App faster with Ruby and NodeJS
DataStax: 0 to App faster with Ruby and NodeJSDataStax: 0 to App faster with Ruby and NodeJS
DataStax: 0 to App faster with Ruby and NodeJS
 
Building Web-API without Rails, Registration or SMS
Building Web-API without Rails, Registration or SMSBuilding Web-API without Rails, Registration or SMS
Building Web-API without Rails, Registration or SMS
 
Play! Framework for JavaEE Developers
Play! Framework for JavaEE DevelopersPlay! Framework for JavaEE Developers
Play! Framework for JavaEE Developers
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development
 
Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Events
 
Data models in Angular 1 & 2
Data models in Angular 1 & 2Data models in Angular 1 & 2
Data models in Angular 1 & 2
 
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
EWD 3 Training Course Part 41: Building a React.js application with QEWD, Part 5
 
fog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloudfog or: How I Learned to Stop Worrying and Love the Cloud
fog or: How I Learned to Stop Worrying and Love the Cloud
 
Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
Webauthn Tutorial
Webauthn TutorialWebauthn Tutorial
Webauthn Tutorial
 
soft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.jssoft-shake.ch - Hands on Node.js
soft-shake.ch - Hands on Node.js
 
Intro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran MizrahiIntro To JavaScript Unit Testing - Ran Mizrahi
Intro To JavaScript Unit Testing - Ran Mizrahi
 
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
fog or: How I Learned to Stop Worrying and Love the Cloud (OpenStack Edition)
 
How to build a High Performance PSGI/Plack Server
How to build a High Performance PSGI/Plack Server How to build a High Performance PSGI/Plack Server
How to build a High Performance PSGI/Plack Server
 

Plus de Rob Tweed

Plus de Rob Tweed (14)

QEWD Update
QEWD UpdateQEWD Update
QEWD Update
 
Data Persistence as a Language Feature
Data Persistence as a Language FeatureData Persistence as a Language Feature
Data Persistence as a Language Feature
 
LNUG: Having Your Node.js Cake and Eating It Too
LNUG: Having Your Node.js Cake and Eating It TooLNUG: Having Your Node.js Cake and Eating It Too
LNUG: Having Your Node.js Cake and Eating It Too
 
QEWD.js: Have your Node.js Cake and Eat It Too
QEWD.js: Have your Node.js Cake and Eat It TooQEWD.js: Have your Node.js Cake and Eat It Too
QEWD.js: Have your Node.js Cake and Eat It Too
 
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Servicesewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
ewd-qoper8-vistarpc: Exposing VistA's RPCs as REST Services
 
qewd-ripple: The Ripple OSI Middle Tier
qewd-ripple: The Ripple OSI Middle Tierqewd-ripple: The Ripple OSI Middle Tier
qewd-ripple: The Ripple OSI Middle Tier
 
EWD 3 Training Course Part 42: The QEWD Docker Appliance
EWD 3 Training Course Part 42: The QEWD Docker ApplianceEWD 3 Training Course Part 42: The QEWD Docker Appliance
EWD 3 Training Course Part 42: The QEWD Docker Appliance
 
EWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session LockingEWD 3 Training Course Part 35: QEWD Session Locking
EWD 3 Training Course Part 35: QEWD Session Locking
 
EWD 3 Training Course Part 33: Configuring QEWD to use CORS
EWD 3 Training Course Part 33: Configuring QEWD to use CORSEWD 3 Training Course Part 33: Configuring QEWD to use CORS
EWD 3 Training Course Part 33: Configuring QEWD to use CORS
 
EWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPS
EWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPSEWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPS
EWD 3 Training Course Part 32: Configuring QEWD to use SSL/HTTPS
 
EWD 3 Training Course Part 26: Event-driven Indexing
EWD 3 Training Course Part 26: Event-driven IndexingEWD 3 Training Course Part 26: Event-driven Indexing
EWD 3 Training Course Part 26: Event-driven Indexing
 
EWD 3 Training Course Part 25: Document Database Capabilities
EWD 3 Training Course Part 25: Document Database CapabilitiesEWD 3 Training Course Part 25: Document Database Capabilities
EWD 3 Training Course Part 25: Document Database Capabilities
 
EWD 3 Training Course Part 24: Traversing a Document's Leaf Nodes
EWD 3 Training Course Part 24: Traversing a Document's Leaf NodesEWD 3 Training Course Part 24: Traversing a Document's Leaf Nodes
EWD 3 Training Course Part 24: Traversing a Document's Leaf Nodes
 
EWD 3 Training Course Part 23: Traversing a Range using DocumentNode Objects
EWD 3 Training Course Part 23: Traversing a Range using DocumentNode ObjectsEWD 3 Training Course Part 23: Traversing a Range using DocumentNode Objects
EWD 3 Training Course Part 23: Traversing a Range using DocumentNode Objects
 

Dernier

%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 

Dernier (20)

WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni%in Benoni+277-882-255-28 abortion pills for sale in Benoni
%in Benoni+277-882-255-28 abortion pills for sale in Benoni
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 

EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services

  • 1. Copyright © 2016 M/Gateway Developments Ltd EWD 3 Training Course Part 43 Using JSON Web Tokens with QEWD REST Services Rob Tweed Director, M/Gateway Developments Ltd Twitter: @rtweed
  • 2. Copyright © 2016 M/Gateway Developments Ltd Using JSON Web Tokens with QEWD REST Services • This part of the course assumes that you've taken, at least: • Part 2: Overview of EWD 3 – https://www.slideshare.net/robtweed/ewd-3-overview • Part 4: Installing & Configuring QEWD – https://www.slideshare.net/robtweed/installing-configuring-ewdxpress • Part 31: Using QEWD for Web and REST Services – http://www.slideshare.net/robtweed/ewd-3-training-course-part-31-ewdxpress-for-web-and-rest-services
  • 3. Copyright © 2016 M/Gateway Developments Ltd JSON Web Tokens: Background • For an introduction on JSON Web Tokens (JWTs), what they are, how they work and when and why they should be considered, see this presentation on QEWD and JWTs: • https://www.slideshare.net/robtweed/qewdjs-json-web-tokens-microservices
  • 4. Copyright © 2016 M/Gateway Developments Ltd Moving to JWTs • In this course, we'll change the example application that was described in Part 31 – From using QEWD server-side Sessions – To using browser-side JWTs
  • 5. Copyright © 2016 M/Gateway Developments Ltd Our original QEWD startup file var config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' } }; var routes = [ {path: '/api', module: 'myRestService'} ]; var qewd = require('qewd').master; qewd.start(config, routes); ~/qewd/rest.js
  • 6. Copyright © 2016 M/Gateway Developments Ltd Tell QEWD to enable JWTs var config = { managementPassword: 'keepThisSecret!', serverName: 'QEWD REST Server', port: 8080, poolSize: 2, database: { type: 'gtm' }, jwt: { secret: 'someSecret123' } }; var routes = [ {path: '/api', module: 'myRestService'} ]; var qewd = require('qewd').master; qewd.start(config, routes); The secret can be any text string you want. The longer and less guessable the better
  • 7. Copyright © 2016 M/Gateway Developments Ltd Modify the Worker Process Handler Module • Instead of standard server-side QEWD Sessions: – /api/login should create a new JWT • Send it as the token response just as before
  • 8. Copyright © 2016 M/Gateway Developments Ltd Modify the Worker Process Handler Module • Instead of standard server-side QEWD Sessions: – /api/login should create a new JWT • Send it as the token response just as before – All other routes should include the JWT in the Authorization Header • Authorization: Bearer {{JWT}}
  • 9. Copyright © 2016 M/Gateway Developments Ltd Modify the Worker Process Handler Module • Instead of standard server-side QEWD Sessions: – /api/login should create a new JWT • Send it as the token response just as before – All other routes should include the JWT in the Authorization Header • Authorization: Bearer {{JWT}} – Validate the incoming JWT and use its payload to get/set session values
  • 10. Copyright © 2016 M/Gateway Developments Ltd Edit the handler module • ~/qewd/node_modules/myRestService.js • All we need to do is: – Modify the login() function – Modify the beforeHandler() function
  • 11. Copyright © 2016 M/Gateway Developments Ltd Modify the Worker Process Handler Module • Instead of standard server-side QEWD Sessions: – /api/login should create a new JWT • Send it as the token response just as before – All other routes should include the JWT in the Authorization Header • Authorization: Bearer {{JWT}} – Validate the incoming JWT and use its payload to get/set session values
  • 12. Copyright © 2016 M/Gateway Developments Ltd Original Login Function function login(args, finished) { var username = args.req.body.username; if (!username || username === '') { return finished({error: 'You must provide a username'}); } var password = args.req.body.password; if (!password || password === '') { return finished({error: 'You must provide a password'}); } if (username !== 'rob') return finished({error: 'Invalid username'}); if (password !== 'secret') return finished({error: 'Invalid password'}); var session = this.sessions.create('testWebService', 3600); session.authenticated = true; session.data.$('username').value = username; finished({token: session.token}); }
  • 13. Copyright © 2016 M/Gateway Developments Ltd Change to use JWTs function login(args, finished) { var username = args.req.body.username; if (!username || username === '') { return finished({error: 'You must provide a username'}); } var password = args.req.body.password; if (!password || password === '') { return finished({error: 'You must provide a password'}); } if (username !== 'rob') return finished({error: 'Invalid username'}); if (password !== 'secret') return finished({error: 'Invalid password'}); var session = this.jwt.handlers.createRestSession.call(this, args); session.welcomeText = 'Welcome ' + username; session.username = username; session.authenticated = true; session.timeout = 1200; var jwt = this.jwt.handlers.setJWT.call(this, session); finished({token: jwt}); }
  • 14. Copyright © 2016 M/Gateway Developments Ltd Change to use JWTs function login(args, finished) { var username = args.req.body.username; if (!username || username === '') { return finished({error: 'You must provide a username'}); } var password = args.req.body.password; if (!password || password === '') { return finished({error: 'You must provide a password'}); } if (username !== 'rob') return finished({error: 'Invalid username'}); if (password !== 'secret') return finished({error: 'Invalid password'}); var session = this.jwt.handlers.createRestSession.call(this, args); session.welcomeText = 'Welcome ' + username; session.username = username; session.authenticated = true; session.timeout = 1200; var jwt = this.jwt.handlers.setJWT.call(this, session); finished({token: jwt}); } Create a new JWT-compatible Session object, using information from the request this.jwt.handlers provides the APIs you'll need for JWT Handling
  • 15. Copyright © 2016 M/Gateway Developments Ltd Change to use JWTs function login(args, finished) { var username = args.req.body.username; if (!username || username === '') { return finished({error: 'You must provide a username'}); } var password = args.req.body.password; if (!password || password === '') { return finished({error: 'You must provide a password'}); } if (username !== 'rob') return finished({error: 'Invalid username'}); if (password !== 'secret') return finished({error: 'Invalid password'}); var session = this.jwt.handlers.createRestSession.call(this, args); session.welcomeText = 'Welcome ' + username; session.username = username; session.authenticated = true; session.timeout = 1200; var jwt = this.jwt.handlers.setJWT.call(this, session); finished({token: jwt}); } Add some extra properties of our own to the Session Object
  • 16. Copyright © 2016 M/Gateway Developments Ltd Change to use JWTs function login(args, finished) { var username = args.req.body.username; if (!username || username === '') { return finished({error: 'You must provide a username'}); } var password = args.req.body.password; if (!password || password === '') { return finished({error: 'You must provide a password'}); } if (username !== 'rob') return finished({error: 'Invalid username'}); if (password !== 'secret') return finished({error: 'Invalid password'}); var session = this.jwt.handlers.createRestSession.call(this, args); session.welcomeText = 'Welcome ' + username; session.username = username; session.authenticated = true; session.timeout = 1200; var jwt = this.jwt.handlers.setJWT.call(this, session); finished({token: jwt}); } The authenticated and timeout properties are special built-in ones timeout specifies how long before the JWT expires
  • 17. Copyright © 2016 M/Gateway Developments Ltd Change to use JWTs function login(args, finished) { var username = args.req.body.username; if (!username || username === '') { return finished({error: 'You must provide a username'}); } var password = args.req.body.password; if (!password || password === '') { return finished({error: 'You must provide a password'}); } if (username !== 'rob') return finished({error: 'Invalid username'}); if (password !== 'secret') return finished({error: 'Invalid password'}); var session = this.jwt.handlers.createRestSession.call(this, args); session.welcomeText = 'Welcome ' + username; session.username = username; session.authenticated = true; session.timeout = 1200; var jwt = this.jwt.handlers.setJWT.call(this, session); finished({token: jwt}); } Create a JWT from the Session data. The secret you defined in the startup file is used by QEWD to sign the JWT
  • 18. Copyright © 2016 M/Gateway Developments Ltd Change to use JWTs function login(args, finished) { var username = args.req.body.username; if (!username || username === '') { return finished({error: 'You must provide a username'}); } var password = args.req.body.password; if (!password || password === '') { return finished({error: 'You must provide a password'}); } if (username !== 'rob') return finished({error: 'Invalid username'}); if (password !== 'secret') return finished({error: 'Invalid password'}); var session = this.jwt.handlers.createRestSession.call(this, args); session.welcomeText = 'Welcome ' + username; session.username = username; session.authenticated = true; session.timeout = 1200; var jwt = this.jwt.handlers.setJWT.call(this, session); finished({token: jwt}); } Finally, return the JWT as the response
  • 19. Copyright © 2016 M/Gateway Developments Ltd Start QEWD using your startup file cd ~/qewd node rest
  • 20. Copyright © 2016 M/Gateway Developments Ltd Try out the /api/login Request
  • 21. Copyright © 2016 M/Gateway Developments Ltd Here's our JWT
  • 22. Copyright © 2016 M/Gateway Developments Ltd Inspecting a JWT • Use: – https://jwt.io/
  • 23. Copyright © 2016 M/Gateway Developments Ltd Inspecting a JWT
  • 24. Copyright © 2016 M/Gateway Developments Ltd Here's our JWT A JWT has 3 Base64-encoded parts, separated by a "."
  • 25. Copyright © 2016 M/Gateway Developments Ltd Here's our JWT We're only really interested in the middle bit – the payload
  • 26. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded Anyone can Base64 Decode the payload of a JWT Secret is not required for this
  • 27. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded Here's the timeout we set
  • 28. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded …and the other properties we set in the Session
  • 29. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded These are reserved JWT payload properties QEWD created them for you Known as "reserved claims"
  • 30. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded This was added by QEWD, using the incoming Request payload data. It's used by QEWD internally
  • 31. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded The qewd property/claim is encrypted using the Secret, so is only usable by anyone with access to the Secret. It contains data for use in the QEWD Back-end only
  • 32. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded You can optionally add data into this private claim, but only from within your worker process handler functions: see later
  • 33. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded If a client returning a JWT makes any changes to the payload, the signature will no longer match, so it will be rejected by QEWD
  • 34. Copyright © 2016 M/Gateway Developments Ltd Modify the Worker Process Handler Module • Instead of standard server-side QEWD Sessions: – /api/login should create a new JWT • Send it as the token response just as before – All other routes should include the JWT in the Authorization Header • Authorization: Bearer {{JWT}} – Validate the incoming JWT and use its payload to get/set session values
  • 35. Copyright © 2016 M/Gateway Developments Ltd Add the JWT Authorization Header
  • 36. Copyright © 2016 M/Gateway Developments Ltd Modify the Worker Process Handler Module • Instead of standard server-side QEWD Sessions: – /api/login should create a new JWT • Send it as the token response just as before – All other routes should include the JWT in the Authorization Header • Authorization: Bearer {{JWT}} – Validate the incoming JWT and use its payload to get/set session values
  • 37. Copyright © 2016 M/Gateway Developments Ltd Edit the handler module • ~/qewd/node_modules/myRestService.js • All we need to do is: – Modify the login() function – Modify the beforeHandler() function
  • 38. Copyright © 2016 M/Gateway Developments Ltd Here's the original beforeHandler() function beforeHandler: function(req, finished) { if (req.path !== '/api/login') { return this.sessions.authenticateRestRequest(req, finished); } }, Using server-side QEWD Sessions
  • 39. Copyright © 2016 M/Gateway Developments Ltd Modified to use JWTs beforeHandler: function(req, finished) { if (req.path !== '/api/login') { return this.jwt.handlers.validateRestRequest.call(this, req, finished); } }, Change to use this API - Checks the JWT's signature using the Secret - Checks if the JWT has expired - Unpacks the JWT payload into the Session object - Decrypts the qewd claim
  • 40. Copyright © 2016 M/Gateway Developments Ltd We'll try the /api/search API • But first we need to check its handler function: init: function(application) { routes = [ { url: '/api/search', //method: 'GET', handler: search },
  • 41. Copyright © 2016 M/Gateway Developments Ltd Original /api/search handler function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); finished({ test: 'finished ok', username: args.session.data.$('username').value }); }
  • 42. Copyright © 2016 M/Gateway Developments Ltd Original /api/search handler function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); finished({ test: 'finished ok', username: args.session.data.$('username').value }); } Will display the args object To the QEWD Node.js console
  • 43. Copyright © 2016 M/Gateway Developments Ltd Original /api/search handler function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); finished({ test: 'finished ok', username: args.session.data.$('username').value }); } Returns the username from the back-end QEWD Session
  • 44. Copyright © 2016 M/Gateway Developments Ltd Change it to use the JWT-derived Session function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); finished({ test: 'finished ok', username: args.session.username }); } args.session now contains the Session object, containing the JWT payload QEWD did this for us automatically
  • 45. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and Try It
  • 46. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and Try It
  • 47. Copyright © 2016 M/Gateway Developments Ltd Take a look at the QEWD Node.js Console Log *** search args: { "req": { "type": "ewd-qoper8-express", "path": "/api/search", "method": "GET", "headers": { "host": "192.168.1.117:8080", "authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MD…", "content-type": "application/json" }, "params": { "type": "search" }, "query": {}, "body": {}, "ip": "::ffff:192.168.1.74", "ips": [], "application": "api", "expressType": "search", …... Here's the args object
  • 48. Copyright © 2016 M/Gateway Developments Ltd Scroll down further… "session": { "exp": 1503046402, "iat": 1503045202, "iss": "qewd.jwt", "application": "api", "timeout": 1200, "qewd": { "ipAddress": "::ffff:192.168.1.74", "authenticated": true }, "welcomeText": "Welcome rob", "username": "rob", "qewd_list": { "ipAddress": true, "authenticated": true }, "ipAddress": "::ffff:192.168.1.74", "authenticated": true } } Here's args.session Contains the JWT payload values
  • 49. Copyright © 2016 M/Gateway Developments Ltd args.session "session": { "exp": 1503046402, "iat": 1503045202, "iss": "qewd.jwt", "application": "api", "timeout": 1200, "qewd": { "ipAddress": "::ffff:192.168.1.74", "authenticated": true }, "welcomeText": "Welcome rob", "username": "rob", "qewd_list": { "ipAddress": true, "authenticated": true }, "ipAddress": "::ffff:192.168.1.74", "authenticated": true } } Here's the username value that was added to the JWT Session by the login function
  • 50. Copyright © 2016 M/Gateway Developments Ltd args.session "session": { "exp": 1503046402, "iat": 1503045202, "iss": "qewd.jwt", "application": "api", "timeout": 1200, "qewd": { "ipAddress": "::ffff:192.168.1.74", "authenticated": true }, "welcomeText": "Welcome rob", "username": "rob", "qewd_list": { "ipAddress": true, "authenticated": true }, "ipAddress": "::ffff:192.168.1.74", "authenticated": true } } But also notice the qewd claim It's been decrypted
  • 51. Copyright © 2016 M/Gateway Developments Ltd args.session "session": { "exp": 1503046402, "iat": 1503045202, "iss": "qewd.jwt", "application": "api", "timeout": 1200, "qewd": { "ipAddress": "::ffff:192.168.1.74", "authenticated": true }, "welcomeText": "Welcome rob", "username": "rob", "qewd_list": { "ipAddress": true, "authenticated": true }, "ipAddress": "::ffff:192.168.1.74", "authenticated": true } } And its properties have been copied to args.session, as properties in their own right
  • 52. Copyright © 2016 M/Gateway Developments Ltd JWT-based Session • Your handler functions can add/change/delete properties within the Session by accessing the args.session properties • Don't modify the reserved claim properties – iss – exp – iat – application
  • 53. Copyright © 2016 M/Gateway Developments Ltd JWT-based Session • By default, any properties you add to the Session will be visible within the JWT payload (after Base64 decoding) • We saw this with the username and welcomeText fields – Added in the login() function – We cut and pasted the JWT into the jwt.io Inspector screen
  • 54. Copyright © 2016 M/Gateway Developments Ltd Here's the login() function function login(args, finished) { var username = args.req.body.username; if (!username || username === '') { return finished({error: 'You must provide a username'}); } var password = args.req.body.password; if (!password || password === '') { return finished({error: 'You must provide a password'}); } if (username !== 'rob') return finished({error: 'Invalid username'}); if (password !== 'secret') return finished({error: 'Invalid password'}); var session = this.jwt.handlers.createRestSession.call(this, args); session.welcomeText = 'Welcome ' + username; session.username = username; session.authenticated = true; session.timeout = 1200; var jwt = this.jwt.handlers.setJWT.call(this, session); finished({token: jwt}); } username and welcomeText added to the Session Object
  • 55. Copyright © 2016 M/Gateway Developments Ltd Inspecting a JWT
  • 56. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded
  • 57. Copyright © 2016 M/Gateway Developments Ltd JWT-based Session • There may be properties/values that you want to add to the JWT/Session that are visible and usable in your back-end handler functions, but too sensitive to be visible to the client/user • QEWD makes this easy
  • 58. Copyright © 2016 M/Gateway Developments Ltd JWT-based Session • There may be properties/values that you want to add to the JWT/Session that are visible and usable in your back-end handler functions, but too sensitive to be visible to the client/user • QEWD makes this easy – Let's make the username secret, but leave the welcomeText visible
  • 59. Copyright © 2016 M/Gateway Developments Ltd Edit the login() function function login(args, finished) { var username = args.req.body.username; if (!username || username === '') { return finished({error: 'You must provide a username'}); } var password = args.req.body.password; if (!password || password === '') { return finished({error: 'You must provide a password'}); } if (username !== 'rob') return finished({error: 'Invalid username'}); if (password !== 'secret') return finished({error: 'Invalid password'}); var session = this.jwt.handlers.createRestSession.call(this, args); session.welcomeText = 'Welcome ' + username; session.username = username; session.makeSecret('username'); session.authenticated = true; session.timeout = 1200; var jwt = this.jwt.handlers.setJWT.call(this, session); finished({token: jwt}); } Just add this
  • 60. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD. Send /api/login
  • 61. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD. Send /api/login Copy the JWT
  • 62. Copyright © 2016 M/Gateway Developments Ltd Paste it into the jwt.io Inspector
  • 63. Copyright © 2016 M/Gateway Developments Ltd Paste it into the jwt.io Inspector welcomeText is still visible but username has disappeared It's been encrypted into the qewd claim
  • 64. Copyright © 2016 M/Gateway Developments Ltd Now send /api/search using new JWT
  • 65. Copyright © 2016 M/Gateway Developments Ltd Now send /api/search using new JWT username appears as before
  • 66. Copyright © 2016 M/Gateway Developments Ltd Take a look at args.session in the QEWD Node.js Console Log "session": { "exp": 1503049897, "iat": 1503048697, "iss": "qewd.jwt", "application": "api", "timeout": 1200, "qewd": { "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" }, "welcomeText": "Welcome rob", "qewd_list": { "ipAddress": true, "authenticated": true, "username": true }, "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" }
  • 67. Copyright © 2016 M/Gateway Developments Ltd Take a look at args.session in the QEWD Node.js Console Log "session": { "exp": 1503049897, "iat": 1503048697, "iss": "qewd.jwt", "application": "api", "timeout": 1200, "qewd": { "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" }, "welcomeText": "Welcome rob", "qewd_list": { "ipAddress": true, "authenticated": true, "username": true }, "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" } username is inside the qewd sub-object
  • 68. Copyright © 2016 M/Gateway Developments Ltd Take a look at args.session in the QEWD Node.js Console Log "session": { "exp": 1503049897, "iat": 1503048697, "iss": "qewd.jwt", "application": "api", "timeout": 1200, "qewd": { "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" }, "welcomeText": "Welcome rob", "qewd_list": { "ipAddress": true, "authenticated": true, "username": true }, "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" } And has been added as a property in its own right to args.session
  • 69. Copyright © 2016 M/Gateway Developments Ltd Take a look at args.session in the QEWD Node.js Console Log "session": { "exp": 1503049897, "iat": 1503048697, "iss": "qewd.jwt", "application": "api", "timeout": 1200, "qewd": { "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" }, "welcomeText": "Welcome rob", "qewd_list": { "ipAddress": true, "authenticated": true, "username": true }, "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" } If the JWT is updated, username remains secret. It is removed as a property in its own right before the JWT is created
  • 70. Copyright © 2016 M/Gateway Developments Ltd Take a look at args.session in the QEWD Node.js Console Log "session": { "exp": 1503049897, "iat": 1503048697, "iss": "qewd.jwt", "application": "api", "timeout": 1200, "qewd": { "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" }, "welcomeText": "Welcome rob", "qewd_list": { "ipAddress": true, "authenticated": true, "username": true }, "ipAddress": "::ffff:192.168.1.74", "authenticated": true, "username": "rob" } If the JWT is updated, username remains secret. It is removed as a property in its own right before the JWT is created That's the purpose of this QEWD-managed sub-object
  • 71. Copyright © 2016 M/Gateway Developments Ltd Modifying/Updating the JWT • You may want to add values/objects/arrays to the JWT-based session within your handler functions • If so, you need to create a new JWT using the args.session object and return it with the response • It's a good idea to return an updated JWT even if you don't add/change session data – To update the JWT's expiry time
  • 72. Copyright © 2016 M/Gateway Developments Ltd Modifying/Updating the JWT • Let's make the /api/search handler update the JWT
  • 73. Copyright © 2016 M/Gateway Developments Ltd Here's our search() function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); finished({ test: 'finished ok', username: args.session.username }); }
  • 74. Copyright © 2016 M/Gateway Developments Ltd Edit the search() function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); args.session.ranSearchAt = Date.now(); finished({ test: 'finished ok', username: args.session.username }); } Add a new property – ranSearchAt - to args.session
  • 75. Copyright © 2016 M/Gateway Developments Ltd Edit the search() function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); args.session.ranSearchAt = Date.now(); var jwt = this.jwt.handlers.setJWT.call(this, args.session); finished({ test: 'finished ok', username: args.session.username }); } Create a new JWT using args.session
  • 76. Copyright © 2016 M/Gateway Developments Ltd Edit the search() function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); args.session.ranSearchAt = Date.now(); var jwt = this.jwt.handlers.setJWT.call(this, args.session); finished({ test: 'finished ok', username: args.session.username, token: jwt }); } Return the new JWT with the response
  • 77. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and send /api/search
  • 78. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and send /api/search Here's the new JWT – let's inspect it
  • 79. Copyright © 2016 M/Gateway Developments Ltd The new JWT
  • 80. Copyright © 2016 M/Gateway Developments Ltd The new JWT Here's the field we added
  • 81. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and send /api/search Where is username?
  • 82. Copyright © 2016 M/Gateway Developments Ltd Look in the search() function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); args.session.ranSearchAt = Date.now(); var jwt = this.jwt.handlers.setJWT.call(this, args.session); finished({ test: 'finished ok', username: args.session.username, token: jwt }); } We're asking it to send the username using the value in args.session.username
  • 83. Copyright © 2016 M/Gateway Developments Ltd Look in the search() function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); args.session.ranSearchAt = Date.now(); var jwt = this.jwt.handlers.setJWT.call(this, args.session); finished({ test: 'finished ok', username: args.session.username, token: jwt }); } We're asking it to send the username using the value in args.session.username But we're doing this after we created the new JWT. In doing so, all secret fields have been removed from args.session So args.session.username no longer exists
  • 84. Copyright © 2016 M/Gateway Developments Ltd Edit the search() function function search(args, finished) { console.log('*** search args: ' + JSON.stringify(args, null, 2)); args.session.ranSearchAt = Date.now(); var username = args.session.username; var jwt = this.jwt.handlers.setJWT.call(this, args.session); finished({ test: 'finished ok', username: username, token: jwt }); } Let's get hold of the username value before the JWT is created, and send that value in the response
  • 85. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and Try Again
  • 86. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and Try Again Now username appears as expected
  • 87. Copyright © 2016 M/Gateway Developments Ltd Using JWTs with QEWD REST Services • You now know everything needed to use JWTs with QEWD.js REST Services • JWTs allow a very different approach to authentication and session management – Completely stateless architecture – Does not require any database for session management – State/session info is held by client in the JWT
  • 88. Copyright © 2016 M/Gateway Developments Ltd Using JWTs with QEWD REST Services • JWTs allow you to scale out your QEWD.js systems – Multiple QEWD systems just need to share the same secret • Each defines the same secret text string in their QEWD startup file
  • 89. Copyright © 2016 M/Gateway Developments Ltd JWT security Server Client Both servers share same secret key Server
  • 90. Copyright © 2016 M/Gateway Developments Ltd JWT security Server Client Server Create initial JWT
  • 91. Copyright © 2016 M/Gateway Developments Ltd JWT security Server Client Server Validate and use JWT
  • 92. Copyright © 2016 M/Gateway Developments Ltd QEWD.js Architecture ewd-qoper8 queue Express Node.js socket.io Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process ewd-qoper8 queue Express Node.js socket.io Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process ewd-qoper8 queue Express Node.js socket.io Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Cache GT.M, YottaDB Redis Node.js Worker Process Load Balancer Or Proxy (eg nginx) Same Secret
  • 93. Copyright © 2016 M/Gateway Developments Ltd Using JWTs with QEWD REST Services • JWTs also provide the basis by which you can break out your QEWD.js applications into fine-grained MicroServices, each running in their own separate machine/VM/container • This will be described in the next part of this course.