Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

304 views

Published on

This is part 43 of the EWD 3 Training Course. In this presentation, you'll learn how to use JSON Web Tokens (JWTs) instead of server-side QEWD Sessions in your REST Services

Published in: Software
  • Be the first to comment

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

  1. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 19. Copyright © 2016 M/Gateway Developments Ltd Start QEWD using your startup file cd ~/qewd node rest
  20. 20. Copyright © 2016 M/Gateway Developments Ltd Try out the /api/login Request
  21. 21. Copyright © 2016 M/Gateway Developments Ltd Here's our JWT
  22. 22. Copyright © 2016 M/Gateway Developments Ltd Inspecting a JWT • Use: – https://jwt.io/
  23. 23. Copyright © 2016 M/Gateway Developments Ltd Inspecting a JWT
  24. 24. Copyright © 2016 M/Gateway Developments Ltd Here's our JWT A JWT has 3 Base64-encoded parts, separated by a "."
  25. 25. Copyright © 2016 M/Gateway Developments Ltd Here's our JWT We're only really interested in the middle bit – the payload
  26. 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. 27. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded Here's the timeout we set
  28. 28. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded …and the other properties we set in the Session
  29. 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. 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. 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. 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. 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. 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. 35. Copyright © 2016 M/Gateway Developments Ltd Add the JWT Authorization Header
  36. 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. 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. 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. 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. 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. 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. 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. 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. 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. 45. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and Try It
  46. 46. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and Try It
  47. 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. 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. 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. 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. 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. 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. 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. 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. 55. Copyright © 2016 M/Gateway Developments Ltd Inspecting a JWT
  56. 56. Copyright © 2016 M/Gateway Developments Ltd Our JWT Payload: Decoded
  57. 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. 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. 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. 60. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD. Send /api/login
  61. 61. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD. Send /api/login Copy the JWT
  62. 62. Copyright © 2016 M/Gateway Developments Ltd Paste it into the jwt.io Inspector
  63. 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. 64. Copyright © 2016 M/Gateway Developments Ltd Now send /api/search using new JWT
  65. 65. Copyright © 2016 M/Gateway Developments Ltd Now send /api/search using new JWT username appears as before
  66. 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. 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. 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. 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. 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. 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. 72. Copyright © 2016 M/Gateway Developments Ltd Modifying/Updating the JWT • Let's make the /api/search handler update the JWT
  73. 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. 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. 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. 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. 77. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and send /api/search
  78. 78. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and send /api/search Here's the new JWT – let's inspect it
  79. 79. Copyright © 2016 M/Gateway Developments Ltd The new JWT
  80. 80. Copyright © 2016 M/Gateway Developments Ltd The new JWT Here's the field we added
  81. 81. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and send /api/search Where is username?
  82. 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. 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. 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. 85. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and Try Again
  86. 86. Copyright © 2016 M/Gateway Developments Ltd Restart QEWD and Try Again Now username appears as expected
  87. 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. 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. 89. Copyright © 2016 M/Gateway Developments Ltd JWT security Server Client Both servers share same secret key Server
  90. 90. Copyright © 2016 M/Gateway Developments Ltd JWT security Server Client Server Create initial JWT
  91. 91. Copyright © 2016 M/Gateway Developments Ltd JWT security Server Client Server Validate and use JWT
  92. 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. 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.

×