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.

JSON Web Tokens Will Improve Your Life

172 views

Published on

JSON Web Tokens, or JWTs (pronounced "jots") are an "open, industry standard RFC 7519 method for representing claims securely between two parties" -- but what does that actually *mean*? If you decode the buzzwords, you'll find JWTs solve common problems around authorization for web and mobile apps in a portable, easily implementable fashion -- and you're going to want to use them *everywhere*.

JWTs are designed to be extremely compact -- small enough to be transmitted in an HTTP header, for example -- and can be used in a variety of ways: as authorization tokens, client-side data storage, or even for the implementation of single sign on (SSO) solutions. They're based on a very simple and elegant algorithm that's easy to understand and quickly put to use. JWT implementations are available in virtually every programming language in common use for Web and mobile development.

Unfortunately, learning how to use JWTs can be complicated by the terminology that's commonly used. "Claims", "signatures", "body", "payload" -- a large part of learning how JWTs work is deciphering these buzzwords and understanding how they map onto more familiar programming terms. This talk will focus on reducing this barrier to entry and making JWTs understandable to any programmer.

This talk will cover:
* the structure of a JSON Web Token
* the algorithm for generating one
* available libraries and tooling
* some common scenarios where JWTs can be used.

Particular emphasis will be given as to when and why JWTs provide for better solutions than other methods. Attendees should come away from this talk with a full understanding of how to use JWTs for a variety of purposes, and be ready and eager to put JWTs into use in both personal and professional contexts.

Presented at OpenWest, 12 Jul 2017

Published in: Internet
  • Be the first to comment

  • Be the first to like this

JSON Web Tokens Will Improve Your Life

  1. 1. JSON Web Tokens Will Improve Your Life John SJ Anderson • @genehack | OpenWest • 12 Jul 2017 JWTs WIYL! - OpenWest 2017 – @genehack 1
  2. 2. Hi, I'm John. a/k/a @genehack JWTs WIYL! - OpenWest 2017 – @genehack 2
  3. 3. VP, Technology Infinity Interactive JWTs WIYL! - OpenWest 2017 – @genehack 3
  4. 4. Now that I've been promoted into a management position, I don't get to do all that much coding anymore. When I do end up with a coding project, Sammy helps me out from her cushion under my desk This is my dog, Sammya/k/a @sammyGenehack JWTs WIYL! - OpenWest 2017 – @genehack 4
  5. 5. who's heard of JWTs before this talk? who's using JWTs? So, what's a JWT? JWTs WIYL! - OpenWest 2017 – @genehack 5
  6. 6. jwt.io JWTs WIYL! - OpenWest 2017 – @genehack 6
  7. 7. Sadly, Sammy suffers from the horrible disease RSF -- Resting Stoned Face What Does That Even MeanJWTs WIYL! - OpenWest 2017 – @genehack 7
  8. 8. Holy RFCs, Batman — RFC 7519 - JSON Web Token (JWT) JWTs WIYL! - OpenWest 2017 – @genehack 8
  9. 9. It turns out, it's not just RFC7519 you need to worry about... Holy RFCs, Batman — RFC 7515 - JSON Web Signature (JWS) — RFC 7516 - JSON Web Encryption (JWE) — RFC 7517 - JSON Web Key (JWK) — RFC 7518 - JSON Web Algorithms (JWA) — RFC 7519 - JSON Web Token (JWT) — RFC 7520 - Examples of Protecting Content Using JSON Object Signing and Encryption (JOSE) JWTs WIYL! - OpenWest 2017 – @genehack 9
  10. 10. Sammy found these RFCs a bit …dry JWTs WIYL! - OpenWest 2017 – @genehack 10
  11. 11. Think of JWTs as… — A lightweight alternative to cookies (kinda, sorta) — ...that also works with CLI, mobile, or even desktop apps — An authorization or access control mechanism — ...kinda like OAuth but without losing your will to live — Cross-domain friendly JWTs WIYL! - OpenWest 2017 – @genehack 11
  12. 12. Made of stuff you already know — Plain ol' JSON Objects (POJOs) — Stringified, encoded, and cryptographically signed — Transmitted over HTTP(S) JWTs WIYL! - OpenWest 2017 – @genehack 12
  13. 13. Dot-delim Three parts... Let's look at each of these three parts in a bit more detail What do they look like? — dot-delimited string ('.') — 3 parts — header — payload — signature — Example: xxx.yyyyy.zzz JWTs WIYL! - OpenWest 2017 – @genehack 13
  14. 14. JWT teardown: header — Plain ole JSON object — Base64 encoded — Typically metadata, such as token type and signing algorithm { "alg": "HS256", "typ": "JWT" } JWTs WIYL! - OpenWest 2017 – @genehack 14
  15. 15. JWT teardown: payload — Another Base64-encoded POJO — Contains "claims" – just key-value data — Types of keys: reserved, public, private { "name": "OpenWest", "admin": false, "iat": 1488562999 } JWTs WIYL! - OpenWest 2017 – @genehack 15
  16. 16. JWT teardown: signature — Encoded header POJO, plus — Encoded payload POJO, plus — A secret, plus — Signing algorithm from header alg key JWTs WIYL! - OpenWest 2017 – @genehack 16
  17. 17. I'm going to be showing a fair amount of code in this talk -- maybe a bit too much code -- but I really wanted to drive home how simple and elegant JWTs are, and showing how they actually work on a code level is the best way to do that, IMO In real practice, you'd almost certainly be using a library for most of the code I'm showing, but since the point is how uncomplicated most of these operations are, I wanted to give you some idea of what was happening inside that code For each code sample, I'm going to show the whole code sample -- and it's going to be way too small to read. I'm doing that just so you can see, it's really not that much code. We'll then step through each one in much smaller 3 or 4 line chunks. Also, please be aware that this code has been, in some cases, simplified for the presentation. DON'T BLINDLY COPY & PASTE! A word about my code samples JWTs WIYL! - OpenWest 2017 – @genehack 17
  18. 18. Making a JWT function base64EncodeJson (pojo) { var jsonString = JSON.stringify(pojo); var encoded = new Buffer(jsonString).toString("base64"); return encoded; } function hmacIt (string, secret) { var hmac = crypto.createHmac("sha256" , secret); hmac.update(string); var signature = hmac.digest("hex"); return signature; } var header = { "alg": "HS256", "typ": "JWT" }; var payload = { "name": "OpenWest", "admin": false, "iat": 1488562999 }; var secret = "be wery, wery qwiet, we're hunting JWTs"; var encodedHeader = base64EncodeJson(header); var encodedPayload = base64EncodeJson(payload); var signature = hmacIt(encodedHeader + "." + encodedPayload, secret); var jwt = encodedHeader + "." + encodedPayload + "." + signature; JWTs WIYL! - OpenWest 2017 – @genehack 18
  19. 19. Helper functions function base64EncodeJson (pojo) { var jsonString = JSON.stringify(pojo); var encoded = new Buffer(jsonString) .toString("base64"); return encoded; } JWTs WIYL! - OpenWest 2017 – @genehack 19
  20. 20. Helper functions function hmacIt (string, secret) { var hmac = crypto.createHmac("sha256" , secret); hmac.update(string); var signature = hmac.digest("hex"); return signature; } JWTs WIYL! - OpenWest 2017 – @genehack 20
  21. 21. The actual data var header = { "alg": "HS256", "typ": "JWT" }; var payload = { "name": "OpenWest", "admin": false, "iat": 1488562999 }; var secret = "be wery, wery qwiet, we're hunting JWTs"; JWTs WIYL! - OpenWest 2017 – @genehack 21
  22. 22. Really generating the signature var encodedHeader = base64EncodeJson(header); var encodedPayload = base64EncodeJson(payload); var signature = hmacIt( encodedHeader + "." + encodedPayload, secret ); var jwt = encodedHeader + "." + encodedPayload + "." + signature; JWTs WIYL! - OpenWest 2017 – @genehack 22
  23. 23. Hand-rolled, artisanal JWT console.log(jwt); 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJuYW1lIjoiT3Blbldlc3QiLCJhZG1pbiI6ZmFsc2UsImlhdCI6MTQ4ODU2Mjk5OX0=. 563ccb7afd5386b8e9d194c899a6ffc0ce3c2fb27f4c4d0c3ecc1c926c23a789 ' Key bit: The signature means you can detect any attempts to modify the header or the payload. JWTs WIYL! - OpenWest 2017 – @genehack 23
  24. 24. Validation JWTs WIYL! - OpenWest 2017 – @genehack 24
  25. 25. Validation JWTs WIYL! - OpenWest 2017 – @genehack 25
  26. 26. Validation JWTs WIYL! - OpenWest 2017 – @genehack 26
  27. 27. Validation JWTs WIYL! - OpenWest 2017 – @genehack 27
  28. 28. Libraries for DAYS JWTs WIYL! - OpenWest 2017 – @genehack 28
  29. 29. Frequently more than 1 library for a given platform, with varying degrees of support Libraries for DAYS — .NET, Python, Node, Java, Javascript, Ruby, Perl, Go, PHP — Haskell, Rust, Lua, Scala, Clojure, ObjectiveC, Swift, Delphi — Support for your favorite language/platform is probably not an issue JWTs WIYL! - OpenWest 2017 – @genehack 29
  30. 30. At this point, Sammy perked back up a little bit. Now that we were past the RFC reading stage, and she'd seen how simple and elegant JWTs were conceptually, she starting asking... OK, you've got my a!entionJWTs WIYL! - OpenWest 2017 – @genehack 30
  31. 31. How do I actually use JWTs?JWTs WIYL! - OpenWest 2017 – @genehack 31
  32. 32. there are couple of different ways, because JWTs are intentionally pretty flexible. but one way you'll probably end up using them is as part of a fairly standard authentication/ authorization type flow Basic auth/authz usage (image stolen from jwt.io) JWTs WIYL! - OpenWest 2017 – @genehack 32
  33. 33. Things to be aware of — Payload/header NOT encrypted — …so don't send anything sensitive! — Need to control expiration, re-issue, etc. — Some APIs send a fresh JWT to the client per-request — Sites other than issuing site can receive JWT — …but they must share the secret to validate JWTs WIYL! - OpenWest 2017 – @genehack 33
  34. 34. How is it actually transmi!ed? — Up to you! Various methods: — As part of the URL in a GET — In a POST body — In the Authorization header using Bearer scheme: Authorization: Bearer <token> JWTs WIYL! - OpenWest 2017 – @genehack 34
  35. 35. Sammy isn't very big on theory. She likes to see the actual implementation so she can really understand what's going on... How would you actually use this in an app? JWTs WIYL! - OpenWest 2017 – @genehack 35
  36. 36. Node code for generating a token after a successful login Generate a token on login app.post('/user/login', app.wrap(user_login)); var jwt = require('jwt'); // helper wrapper around 'jsonwebtoken' function * user_login (req, res) { if (! (req.body.email && req.body.password)) { res.status(400); res.json({message: 'invalid request'}); return; } var user = yield _fetch_user_by_email(req.body.email); var claims; if (_pw_validate(user.password, req.body.password)) { claims = { user_id: user.id }; } else { res.status(401); res.header('WWW-Authenticate', 'Bearer realm=myapp'); res.json({ message: 'authorization required' }); return; } // sign the claim set and return the token in a header var token = jwt.sign(claims); res.append('X-MyApp-Token', token); res.status(200); } JWTs WIYL! - OpenWest 2017 – @genehack 36
  37. 37. This code is from an express app, so first we have to declare a route Then we import a helper library that's just a thin wrapper around the jsonwebtoken NPM library. Generate a token on login app.post('/user/login', app.wrap(user_login)); var jwt = require('jwt'); // helper wrapper around 'jsonwebtoken' function * user_login (req, res) { if (! (req.body.email && req.body.password)) { res.status(400); res.json({message: 'invalid request'}); return; } JWTs WIYL! - OpenWest 2017 – @genehack 37
  38. 38. Generate a token on login var user = yield _fetch_user_by_email(req.body.email); var claims; if (_pw_validate(user.password, req.body.password)) { claims = { user_id: user.id }; } else { res.status(401); res.header('WWW-Authenticate', 'Bearer realm=myapp'); res.json({ message: 'authorization required' }); return; } JWTs WIYL! - OpenWest 2017 – @genehack 38
  39. 39. Generate a token on login // sign the claim set and return the token in a header var token = jwt.sign(claims); res.append('X-MyApp-Token', token); res.status(200); } JWTs WIYL! - OpenWest 2017 – @genehack 39
  40. 40. OK, that's how you make one. How do you validate it? JWTs WIYL! - OpenWest 2017 – @genehack 40
  41. 41. Again, because this is Express, we can do validation in a middleware. That'll make sure it happens on every request. Validate with a middleware // enable JWT-verification middleware var jwt = require('jwt'); // helper wrapper around 'jsonwebtoken' app.use(function (req, res, next) { // initialize the jwt object req.jwt = {}; // now parse the Authorization header if it exists Promise.resolve(req.headers.authorization).then(function (auth) { // If the Authorization header is present and employs the correct // Bearar scheme, extract the token and attempt to verify it. if (auth) { var scheme = auth.split(' ')[0]; var token = auth.split(' ')[1]; if (scheme == 'Bearer') { return jwt.verify(token).catch(function (error) { throw new Error('failed to verify claim'); }); } } throw new Error('authorization not attempted'); }) .then(function (payload) { req.jwt = payload; next(); }) .catch(function (error) { // Allow login without JWT if (req.path == '/user/login' && req.method == 'POST') { return next(); } res.status(401); res.header('WWW-Authenticate', 'Bearer realm=myapp'); res.json({ message: 'authorization required' }); }); }); JWTs WIYL! - OpenWest 2017 – @genehack 41
  42. 42. Validate with a middleware // enable JWT-verification middleware var jwt = require('jwt'); // helper wrapper around 'jsonwebtoken' app.use(function (req, res, next) { // initialize the jwt object req.jwt = {}; JWTs WIYL! - OpenWest 2017 – @genehack 42
  43. 43. Validate with a middleware // now parse the Authorization header if it exists Promise.resolve(req.headers.authorization).then(function (auth) { // If the Authorization header is present and employs the correct // Bearar scheme, extract the token and attempt to verify it. if (auth) { var scheme = auth.split(' ')[0]; var token = auth.split(' ')[1]; if (scheme === 'Bearer') { return jwt.verify(token).catch(function (error) { throw new Error('failed to verify claim'); }); } } throw new Error('authorization not attempted'); }) JWTs WIYL! - OpenWest 2017 – @genehack 43
  44. 44. Validate with a middleware .then(function (payload) { req.jwt = payload; next(); }) JWTs WIYL! - OpenWest 2017 – @genehack 44
  45. 45. Validate with a middleware .catch(function (error) { // Allow login without JWT if (req.path == '/user/login' && req.method == 'POST') { return next(); } res.status(401); res.header('WWW-Authenticate', 'Bearer realm=myapp'); res.json({ message: 'authorization required' }); }); }); JWTs WIYL! - OpenWest 2017 – @genehack 45
  46. 46. At this point, Sammy was pretty impressed and happy, and was making plans to use JWTs in all her future projects. But she wondered if there was anything else JWTs could do for her... That's cool. What else you got? JWTs WIYL! - OpenWest 2017 – @genehack 46
  47. 47. Pre-signed Content RequestsJWTs WIYL! - OpenWest 2017 – @genehack 47
  48. 48. Application that needs to store and display various documents for users, including images We want to display some things -- images, e.g. -- in the browser Document store application — Client-side Angular — Uses JWT for authentication and sessions — Uses Authorization: Bearer scheme JWTs WIYL! - OpenWest 2017 – @genehack 48
  49. 49. The browser isn't going to send any special authorization header, it's just going to see a normal <img> link or whatever PROBLEM! How do you display or download images via browser? JWTs WIYL! - OpenWest 2017 – @genehack 49
  50. 50. SOLUTION JWTs WIYL! - OpenWest 2017 – @genehack 50
  51. 51. JWTs, of course JWTs WIYL! - OpenWest 2017 – @genehack 51
  52. 52. What talk did you think this was?JWTs WIYL! - OpenWest 2017 – @genehack 52
  53. 53. Solution — Generate a claim containing document ID: { "iat": 1497105117 "exp": 1497105177 "doc": 345345 } — NOTE: short expiration time JWTs WIYL! - OpenWest 2017 – @genehack 53
  54. 54. Solution — Sign it and put it in a URL: /content/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpYXQiOjE0OTcxMDUxMTcsImV4cCI6MTQ5NzEwNTE3Ny wiZG9jIjozNDUzNDV9.fKKCZgc2ckeONF9ELOcc9EgS-UPr CBX2bwoPmxjStdQ JWTs WIYL! - OpenWest 2017 – @genehack 54
  55. 55. Solution — Then on the server side, when you get a request that looks like: GET /content/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpYXQiOjE0OTcxMDUxMTcsImV4cCI6MTQ5NzEwNTE3Ny wiZG9jIjozNDUzNDV9.fKKCZgc2ckeONF9ELOcc9EgS-UPr CBX2bwoPmxjStdQ — Extract the token and validate — Get the document ID from the payload — Send back that document! JWTs WIYL! - OpenWest 2017 – @genehack 55
  56. 56. what else can you do? FAR OUT MAAAAAN JWTs WIYL! - OpenWest 2017 – @genehack 56
  57. 57. This is actually the feature of JWTs that inspired me to give this talk, because JWTs provide an easy solution for a problem that I feel like I've run into time and time again in my coding career Recurring dilemma: 'lightweight' access control JWTs WIYL! - OpenWest 2017 – @genehack 57
  58. 58. leave it wide open or implement full login ...and then user management, admin screens, etc. or oauth -- but i've never had a good experience using oauth. anybody here like oauth? Recurring dilemma: 'lightweight' access control — Option 1: leave it wide open — a/k/a the MongoDB or WTF,YOLO! pattern — Option 2: implement full authn/authz subsystem — …again — Option 3: OAuth !!!!!! JWTs WIYL! - OpenWest 2017 – @genehack 58
  59. 59. photo credits * open = https://www.flickr.com/photos/ keoni101/5356662124/ Where's the middle ground? JWTs WIYL! - OpenWest 2017 – @genehack 59
  60. 60. photo credits * vault = https://www.flickr.com/photos/ goodfeeling/24796188573/ Where's the middle ground? JWTs WIYL! - OpenWest 2017 – @genehack 60
  61. 61. photo credit = https://www.flickr.com/photos/slemmon/ 4938498564 A screen door for APIs JWTs WIYL! - OpenWest 2017 – @genehack 61
  62. 62. Authorization without authentication — Scenario: — You have an API — You don't want to make anybody authenticate to use it — You don't want it wide open to the Internet either — a/k/a authz without authn JWTs WIYL! - OpenWest 2017 – @genehack 62
  63. 63. Solution: JWT with RSA keys — Another option for secret: RSA key-pair — Include the public key in the JWT header using JWK — JSON Web Key, natch — Allows clients of your API to make tokens — …which you can verify JWTs WIYL! - OpenWest 2017 – @genehack 63
  64. 64. To set it up: — Give authorized API client an RSA key-pair — Record the fingerprint of the public key (important later!) — You can even let the client generate the key-pair — You just need the public key fingerprint JWTs WIYL! - OpenWest 2017 – @genehack 64
  65. 65. On the client side: — They make a JWT, using the private key to sign — They include the public key in the header — Include iat (issued-at) and exp (expires) claims — Send JWT in with API request JWTs WIYL! - OpenWest 2017 – @genehack 65
  66. 66. On the API side: — Get the public key out of the header — Validate the signature using the public key — Validate that public key fingerprint is white-listed — Signature produced with private key — Public key is white-listed — Therefore we know JWT is valid! JWTs WIYL! - OpenWest 2017 – @genehack 66
  67. 67. Things to be aware of: — You still want to validate iat and exp and any other rules — Your library should probably do that stuff for you, mostly — Again, nothing is encrypted, so don't plan on sensitive stuff in the payload or header JWTs WIYL! - OpenWest 2017 – @genehack 67
  68. 68. where's the code?JWTs WIYL! - OpenWest 2017 – @genehack 68
  69. 69. Client side code use Crypt::JWT qw(encode_jwt); use Crypt::PK::RSA; use HTTP::Request; # generate a JWT and POST a request my $pri_key = Crypt::PK::RSA->new('./key.pri'); my $pub_key = Crypt::PK::RSA->new('./key.pub'); my $token = encode_jwt( alg => 'RS512', extra_headers => { jwk => $pub_key->export_key_jwk('public', 1), nonce => undef , }, key => $pri_key , payload => { iat => time() }, relative_exp => 1800, ); HTTP::Request->new( 'POST' => 'https://example.com/endpoint', ['Authorization' => "Bearer $token"], encode_json({ request => 'body' }) ); JWTs WIYL! - OpenWest 2017 – @genehack 69
  70. 70. maybe don't store your keys in files in the same directory as your code... Client side code use Crypt::JWT qw(encode_jwt); use Crypt::PK::RSA; use HTTP::Request; my $pri_key = Crypt::PK::RSA->new('./key.pri'); my $pub_key = Crypt::PK::RSA->new('./key.pub'); JWTs WIYL! - OpenWest 2017 – @genehack 70
  71. 71. Client side code my $token = encode_jwt( alg => 'RS512', extra_headers => { jwk => $pub_key->export_key_jwk('public', 1), nonce => undef , }, key => $pri_key , payload => { iat => time() }, relative_exp => 1800, ); JWTs WIYL! - OpenWest 2017 – @genehack 71
  72. 72. Client side code HTTP::Request->new( 'POST' => 'https://example.com/endpoint', ['Authorization' => "Bearer $token"], encode_json({ request => 'body' }) ); JWTs WIYL! - OpenWest 2017 – @genehack 72
  73. 73. Critical bit:adding the public key to the header extra_headers => { jwk => $pub_key->export_key_jwk('public', 1), }, Critical: find an RSA library that supports exporting keys to JWK format! JWTs WIYL! - OpenWest 2017 – @genehack 73
  74. 74. API side use Crypt::JWT qw(decode_jwt); use Crypt::PK::RSA; use Dancer; use Try::Tiny; my $auth_header = request_header 'Authorization' ; my $token; status_401 unless ( $token ) = $auth_header =~ /^Bearer (.*)$/; # try to decode it and confirm valid sig, # and valid iat and exp claims my( $header, $payload ); try { ( $header, $payload ) = decode_jwt( token => $token , decode_header => 1 , accepted_alg => 'RS512' , verify_iat => 1 , verify_exp => 1 ); }; # no catch block, just drop the error, we're out of here in that case status_401 unless $header and $payload; # check that expiration time is less than one hour status_401 unless $payload->{exp} - $payload->{iat} < 3600; # check that the included public key is on the whitelist my $pk = Crypt::PK::RSA->new; $pk->import_key($header->{jwk}); my $thumbprint = $pk->export_key_jwk_thumbprint; status_401 unless config->{whitelist}{$thumbprint}; # if we get here, we're all good! ... JWTs WIYL! - OpenWest 2017 – @genehack 74
  75. 75. API side: get the token use Crypt::JWT qw(decode_jwt); use Crypt::PK::RSA; use Dancer; use Try::Tiny; my $auth_header = request_header 'Authorization' ; my $token; status_401 unless ( $token ) = $auth_header =~ /^Bearer (.*)$/; JWTs WIYL! - OpenWest 2017 – @genehack 75
  76. 76. API side: decode the token # try to decode it and confirm valid sig, # and valid iat and exp claims my( $header, $payload ); try { ( $header, $payload ) = decode_jwt( token => $token , decode_header => 1 , accepted_alg => 'RS512' , verify_iat => 1 , verify_exp => 1 ); }; # no catch block, just drop the error, we're out of here in that case status_401 unless $header and $payload; JWTs WIYL! - OpenWest 2017 – @genehack 76
  77. 77. API side: decode the token — Key in header wrong? FAILS — Not right algorithm? FAILS — Doesn't have iat and exp? FAILS ALL that validation is happening inside the library, so I don't have to worry about it. — Me? WINS JWTs WIYL! - OpenWest 2017 – @genehack 77
  78. 78. API side: more checks — We specify in the API docs that tokens can only be valid for one hour — Have to check that ourselves — Also need to make sure this isn't some random RSA keypair — Need to make sure we know this public key JWTs WIYL! - OpenWest 2017 – @genehack 78
  79. 79. our api has a rule that the token can't have an expires time more than 1 hour into the future. we also need to make sure the public key fingerprint is on the allowed list one weakness with this scheme is, if a valid token leaks, that allows access to the API until it expires -- so make sure you chose an allowable access window based on an evaluation of that potential impact API side: more validation # check that expiration time is less than one hour status_401 unless $payload->{exp} - $payload->{iat} < 3600; # check that the included public key is on the whitelist my $pk = Crypt::PK::RSA->new; $pk->import_key($header->{jwk}); my $thumbprint = $pk->export_key_jwk_thumbprint; status_401 unless config->{whitelist}{$thumbprint}; JWTs WIYL! - OpenWest 2017 – @genehack 79
  80. 80. API side: THAT'S ALL FOLKS # if we get here, we're all good! — We know the public key in the header by its fingerprint, — so we know the private key was used to sign the JWT — (or it wouldn't validate) — and therefore the JWT is from the private key holder — (who is, by definition, authorized!) JWTs WIYL! - OpenWest 2017 – @genehack 80
  81. 81. IMPORTANT NOTE! This does, of course, depend on the client keeping the private key actually private …but revocation is as simple as removing the fingerprint from the whitelist. JWTs WIYL! - OpenWest 2017 – @genehack 81
  82. 82. More advanced usage — Encrypted payloads (JWE) — Nested JWT See those RFCs! JWTs WIYL! - OpenWest 2017 – @genehack 82
  83. 83. this is sammy's friend pepper. he's a chinese crested, widely acknowledged as the ugliest dog breed ever, sometimes called "oh gawd what's wrong with that dog?!" i would be remiss if i didn't also mention that some folks really don't like JWTs in fact, it's not hard to find articles with titles like "don't ever use jwts never ever" or "jwts will ruin your life" objections seem to fall into one of two categories: first, the RFCs originally had a fairly significant bug. <explain 'none' algorithm bug>. in general, you want to use a library that allows you to specify that tokens have to use a particular algorithm. i would suggest a best practice here is to use a facade pattern wrapper around your JWT library so that secret handling, algoritm choice, etc., are consolidated to a single location and not left up to individual coders. (this advice isn't specific to JWT, of course) the second objection is that the spec in general is too flexible and has too many options. as a perl programmer, this is not an argument that makes a lot of headway with me. JWT backlash JWTs WIYL! - OpenWest 2017 – @genehack 83
  84. 84. Conclusions — JWTs solve some really common problems. — JWTs solve them in a pretty elegant way. — This is really pretty damn cool. JWTs WIYL! - OpenWest 2017 – @genehack 84
  85. 85. Conclusions — JWTs solve some really common problems. — JWTs solve them in a pretty elegant way. — This is really pretty damn cool!!! — You should think about using JWTs. JWTs WIYL! - OpenWest 2017 – @genehack 85
  86. 86. Thanks! — JWT.io / auth0.com folks — OpenWest organizers — YOU! JWTs WIYL! - OpenWest 2017 – @genehack 86
  87. 87. JWTs WIYL! - OpenWest 2017 – @genehack 87
  88. 88. Questions? JWTs WIYL! - OpenWest 2017 – @genehack 88

×