Contenu connexe Similaire à EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services (20) EWD 3 Training Course Part 43: Using JSON Web Tokens with QEWD REST Services1. 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
22. Copyright © 2016 M/Gateway Developments Ltd
Inspecting a JWT
• Use:
– https://jwt.io/
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
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
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
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
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
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.