SlideShare a Scribd company logo
1 of 93
Download to read offline
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.

More Related Content

What's hot

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 QEWDRob Tweed
 
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 ApplicationRob Tweed
 
QEWD.js, JSON Web Tokens & MicroServices
QEWD.js, JSON Web Tokens & MicroServicesQEWD.js, JSON Web Tokens & MicroServices
QEWD.js, JSON Web Tokens & MicroServicesRob Tweed
 
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 MessagesRob Tweed
 
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 ApplicationsRob Tweed
 
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 SessionRob Tweed
 
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 ServicesRob Tweed
 
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...Rob Tweed
 
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 4Rob Tweed
 
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 QEWDRob Tweed
 
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 ...Rob Tweed
 
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 ModeRob Tweed
 
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 OverviewRob Tweed
 
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 ControlRob Tweed
 
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 3Rob Tweed
 
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 APIsRob Tweed
 
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 ServiceRob Tweed
 
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 QEWDRob Tweed
 
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 StartedRob Tweed
 
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 ObjectRob Tweed
 

What's hot (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
 

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

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 AppsMike Subelsky
 
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.jsSeth McLaughlin
 
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 AppsBastian Hofmann
 
Writing robust Node.js applications
Writing robust Node.js applicationsWriting robust Node.js applications
Writing robust Node.js applicationsTom Croucher
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
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 NodeJSDataStax Academy
 
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 SMSPivorak MeetUp
 
Play! Framework for JavaEE Developers
Play! Framework for JavaEE DevelopersPlay! Framework for JavaEE Developers
Play! Framework for JavaEE DevelopersTeng Shiu Huang
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress DevelopmentAdam Tomat
 
Live Streaming & Server Sent Events
Live Streaming & Server Sent EventsLive Streaming & Server Sent Events
Live Streaming & Server Sent Eventstkramar
 
Data models in Angular 1 & 2
Data models in Angular 1 & 2Data models in Angular 1 & 2
Data models in Angular 1 & 2Adam Klein
 
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 5Rob Tweed
 
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 CloudWesley Beary
 
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 jsFrancois Zaninotto
 
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.jssoft-shake.ch
 
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 MizrahiRan 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
 
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 Masahiro Nagano
 

Similar to 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
 

More from Rob Tweed

Data Persistence as a Language Feature
Data Persistence as a Language FeatureData Persistence as a Language Feature
Data Persistence as a Language FeatureRob Tweed
 
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 TooRob Tweed
 
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 TooRob Tweed
 
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 ServicesRob Tweed
 
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 TierRob Tweed
 
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 ApplianceRob Tweed
 
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 LockingRob Tweed
 
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 CORSRob Tweed
 
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/HTTPSRob Tweed
 
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 IndexingRob Tweed
 
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 CapabilitiesRob Tweed
 
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 NodesRob Tweed
 
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 ObjectsRob Tweed
 

More from 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
 

Recently uploaded

OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingShane Coughlan
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jNeo4j
 
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfRTS corp
 
Revolutionize Your Video Editing with InVideo.io: A Comprehensive Review
Revolutionize Your Video Editing with InVideo.io: A Comprehensive ReviewRevolutionize Your Video Editing with InVideo.io: A Comprehensive Review
Revolutionize Your Video Editing with InVideo.io: A Comprehensive Reviewjw364beach
 
Business Analyzopedia - Your Pocket Gita for Business Analysis
Business Analyzopedia - Your Pocket Gita for Business AnalysisBusiness Analyzopedia - Your Pocket Gita for Business Analysis
Business Analyzopedia - Your Pocket Gita for Business AnalysisDEEPRAJ PATHAK
 
Introduction to Firebase Workshop Slides
Introduction to Firebase Workshop SlidesIntroduction to Firebase Workshop Slides
Introduction to Firebase Workshop Slidesvaideheekore1
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shardsChristopher Curtin
 
OpenMetadata Community Meeting - 4th April, 2024
OpenMetadata Community Meeting - 4th April, 2024OpenMetadata Community Meeting - 4th April, 2024
OpenMetadata Community Meeting - 4th April, 2024OpenMetadata
 
Key Steps in Agile Software Delivery Roadmap
Key Steps in Agile Software Delivery RoadmapKey Steps in Agile Software Delivery Roadmap
Key Steps in Agile Software Delivery RoadmapIshara Amarasekera
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics
 
oracle 23c new features for developer and dba
oracle 23c new features for developer and dbaoracle 23c new features for developer and dba
oracle 23c new features for developer and dbaRemote DBA Services
 
What is Mendix and the concept of low-code development.docx
What is Mendix and the concept of low-code development.docxWhat is Mendix and the concept of low-code development.docx
What is Mendix and the concept of low-code development.docxTechnogeeks
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...Bert Jan Schrijver
 
Transform your Corporate Strategy Office - Harness OnePlan’s Strategic Portfo...
Transform your Corporate Strategy Office - Harness OnePlan’s Strategic Portfo...Transform your Corporate Strategy Office - Harness OnePlan’s Strategic Portfo...
Transform your Corporate Strategy Office - Harness OnePlan’s Strategic Portfo...OnePlan Solutions
 
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdfSteve Caron
 
Mastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxMastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxAS Design & AST.
 
Santander Stream Processing with Apache Flink
Santander Stream Processing with Apache FlinkSantander Stream Processing with Apache Flink
Santander Stream Processing with Apache Flinkconfluent
 
SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?Alexandre Beguel
 
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxUnderstanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxSasikiranMarri
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolsosttopstonverter
 

Recently uploaded (20)

OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full RecordingOpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
OpenChain AI Study Group - Europe and Asia Recap - 2024-04-11 - Full Recording
 
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4jGraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
GraphSummit Madrid - Product Vision and Roadmap - Luis Salvador Neo4j
 
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdfEnhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
Enhancing Supply Chain Visibility with Cargo Cloud Solutions.pdf
 
Revolutionize Your Video Editing with InVideo.io: A Comprehensive Review
Revolutionize Your Video Editing with InVideo.io: A Comprehensive ReviewRevolutionize Your Video Editing with InVideo.io: A Comprehensive Review
Revolutionize Your Video Editing with InVideo.io: A Comprehensive Review
 
Business Analyzopedia - Your Pocket Gita for Business Analysis
Business Analyzopedia - Your Pocket Gita for Business AnalysisBusiness Analyzopedia - Your Pocket Gita for Business Analysis
Business Analyzopedia - Your Pocket Gita for Business Analysis
 
Introduction to Firebase Workshop Slides
Introduction to Firebase Workshop SlidesIntroduction to Firebase Workshop Slides
Introduction to Firebase Workshop Slides
 
2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards2024 DevNexus Patterns for Resiliency: Shuffle shards
2024 DevNexus Patterns for Resiliency: Shuffle shards
 
OpenMetadata Community Meeting - 4th April, 2024
OpenMetadata Community Meeting - 4th April, 2024OpenMetadata Community Meeting - 4th April, 2024
OpenMetadata Community Meeting - 4th April, 2024
 
Key Steps in Agile Software Delivery Roadmap
Key Steps in Agile Software Delivery RoadmapKey Steps in Agile Software Delivery Roadmap
Key Steps in Agile Software Delivery Roadmap
 
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News UpdateVictoriaMetrics Q1 Meet Up '24 - Community & News Update
VictoriaMetrics Q1 Meet Up '24 - Community & News Update
 
oracle 23c new features for developer and dba
oracle 23c new features for developer and dbaoracle 23c new features for developer and dba
oracle 23c new features for developer and dba
 
What is Mendix and the concept of low-code development.docx
What is Mendix and the concept of low-code development.docxWhat is Mendix and the concept of low-code development.docx
What is Mendix and the concept of low-code development.docx
 
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
JavaLand 2024 - Going serverless with Quarkus GraalVM native images and AWS L...
 
Transform your Corporate Strategy Office - Harness OnePlan’s Strategic Portfo...
Transform your Corporate Strategy Office - Harness OnePlan’s Strategic Portfo...Transform your Corporate Strategy Office - Harness OnePlan’s Strategic Portfo...
Transform your Corporate Strategy Office - Harness OnePlan’s Strategic Portfo...
 
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
[ CNCF Q1 2024 ] Intro to Continuous Profiling and Grafana Pyroscope.pdf
 
Mastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptxMastering Project Planning with Microsoft Project 2016.pptx
Mastering Project Planning with Microsoft Project 2016.pptx
 
Santander Stream Processing with Apache Flink
Santander Stream Processing with Apache FlinkSantander Stream Processing with Apache Flink
Santander Stream Processing with Apache Flink
 
SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?SAM Training Session - How to use EXCEL ?
SAM Training Session - How to use EXCEL ?
 
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptxUnderstanding Plagiarism: Causes, Consequences and Prevention.pptx
Understanding Plagiarism: Causes, Consequences and Prevention.pptx
 
eSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration toolseSoftTools IMAP Backup Software and migration tools
eSoftTools IMAP Backup Software and migration tools
 

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.