EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
Transcript of EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services
Copyright © 2016 M/Gateway Developments Ltd
EWD 3 Training CoursePart 43
Using JSON Web Tokenswith QEWD REST Services
Rob TweedDirector, 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 JWTsvar 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 anytext string you want.
The longer and lessguessable 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 Functionfunction 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 JWTsfunction 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 JWTsfunction 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-compatibleSession object, usinginformation from the request
this.jwt.handlers providesthe APIs you'll need for JWTHandling
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTsfunction 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 propertiesof our own to the Session Object
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTsfunction 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 andtimeout properties arespecial built-in ones
timeout specifies howlong before the JWT
expires
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTsfunction 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 fromthe Session data.
The secret you defined in thestartup file is used by QEWD
to sign the JWT
Copyright © 2016 M/Gateway Developments Ltd
Change to use JWTsfunction 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 theJWT as the response
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
…and the other properties we set in the Session
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
These are reserved JWT payload propertiesQEWD 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 incomingRequest payload data. It's used by QEWDinternally
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
The qewd property/claim is encrypted using theSecret, so is only usable by anyone with accessto the Secret. It contains data for use in the QEWDBack-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 handlerfunctions: see later
Copyright © 2016 M/Gateway Developments Ltd
Our JWT Payload: Decoded
If a client returning a JWT makes any changes tothe 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
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-sideQEWD 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 objectTo 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 fromthe 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 containsthe Session object, containingthe JWT payload
QEWD did this for usautomatically
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 payloadvalues
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 usernamevalue that was addedto the JWT Sessionby 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 theqewd 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 havebeen copied toargs.session, asproperties in theirown 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() functionfunction 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 andwelcomeTextadded to the
Session Object
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() functionfunction 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
Paste it into the jwt.io Inspector
welcomeText is still visiblebut username has disappeared
It's been encrypted into the qewdclaim
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 theqewd 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 toargs.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, usernameremains secret. It is removed asa property in its own right before theJWT 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, usernameremains secret. It is removed asa property in its own right before theJWT 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
Here's the new JWT – let's inspect it
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 usernameusing 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 usernameusing the value in args.session.username
But we're doing this after we created thenew JWT. In doing so, all secret fieldshave been removed from args.session
So args.session.username no longerexists
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, andsend that value in the response
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
QEWD.js Architecture
ewd-qoper8queue
Express
Node.js
socket.io
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
ewd-qoper8queue
Express
Node.js
socket.io
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
ewd-qoper8queue
Express
Node.js
socket.io
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
CacheGT.M,YottaDBRedisNode.js
WorkerProcess
Load BalancerOr 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.