Authentication for the REST of us

A presentation at CascadiaJS in November 2019 in Seattle, WA, USA by Divya

Slide 1

Slide 1

THE INTERNET IN THE BEGINNING… username username username ••••••••••• ••••••••••• username username ••••••••••• ••••••••••• username ••••••••••• ••••••••••• ••••••••••• username ••••••••••• username username ••••••••••• ••••••••••• username username username ••••••••••• username ••••••••••• ••••••••••• username username ••••••••••• usern usern ••••••••••• ••••••• ••••••• username ••••••••••• username username ••••••••••• ••••••••••• username username ••••••••••• ••••••••••• username username ••••••••••• username ••••••••••• •••••••••••

Slide 2

Slide 2

THE INTERNET IN THE BEGINNING…

Slide 3

Slide 3

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC J9.eyJhcHBfbWV0YWRhdGEiOnsiYXV0aG9 yaXphdGlvbiI6eyJyb2xlcyI6WyJhZG1pb iIsImVkaXRvciJdfX19.4IKFHH33EXWseN jNIRO4-u5IlSlJOLyibG20qPA4Djs ????????? ????????? ?????????

Slide 4

Slide 4

Slide 5

Slide 5

Authentication for the REST of us Divya Sasidharan @shortdiv

Slide 6

Slide 6

works here Divya Sasidharan

Slide 7

Slide 7

Slide 8

Slide 8

WHY DOES IT MATTER? INTRODUCTION SECURITY STRATEGIES WHERE AUTHENTICATION WHAT WHO WHY WHEN HOW DON’T PANIC AUTHENTICATION INTRODUCTION

Slide 9

Slide 9

INTRODUCTION SECURITY STRATEGIES AUTHENTICATION DON’T PANIC AUTHENTICATION WHO WHAT WHY WHERE WHEN HOW INTRODUCTION WHY DOES IT MATTER?

Slide 10

Slide 10

WHY DOES IT MATTER? AUTHENTICATION WHY DOES IT MATTER?

Slide 11

Slide 11

AUTHENTICATION WHY DOES IT MATTER?

Slide 12

Slide 12

AUTHENTICATION WHY DOES IT MATTER?

Slide 13

Slide 13

AUTHENTICATION

Slide 14

Slide 14

CHARACTERISTICS HISTORY HOW TO HAVE FUN WITH AUTHORIZATION HOW TO NOT CONFUSE YOURSELF WHAT TO AVOID AUTHENTICATION

Slide 15

Slide 15

AUTHORIZATION AUTHENTICATION AUTHORIZATION

Slide 16

Slide 16

AUTHENTICATION AUTHORIZATION User Authenticated: Hitchhiker

Slide 17

Slide 17

AUTHENTICATION AUTHORIZATION ERROR: Hitchhiker NOT AUTHORIZED

Slide 18

Slide 18

AUTHENTICATION AUTHORIZATION

Slide 19

Slide 19

HOW IT WORKS AUTHENTICATION

Slide 20

Slide 20

AUTHENTICATION HOW IT WORKS username •••••••••••

Slide 21

Slide 21

AUTHENTICATION HOW BASIC IT WORKS AUTH Username: FPrefect Password: thisisn0t@dri11 1 RlByZWZlY3Q6dGhpc2lzbjB0QGRya 2 TEx

Slide 22

Slide 22

AUTHENTICATION HOW IT WORKS Username:Password FPrefect:thisisn0t@dri11 Authorization: Basic RlByZWZlY3Q6dGhpc2lzbjB0 QGRyaTEx BASIC AUTH { 3 “id”:”89765-1”, “role”:”hitchhiker”, “email”:”ford@infinidim.com”, … 4 }

Slide 23

Slide 23

AUTHENTICATION HOW IT WORKS BASIC AUTH { “id”:”89765-1”, “role”:”hitchhiker”, “email”:”ford@infinidim.com”, … Authorization: Basic RlByZWZlY3Q6dGhpc2lzbjB0 QGRyaTEx }

Slide 24

Slide 24

AUTHENTICATION HOW IT WORKS BASIC AUTH

Slide 25

Slide 25

AUTHENTICATION HOW IT WORKS BASIC AUTH

Slide 26

Slide 26

AUTHENTICATION HOW IT BASED WORKS SESSION Username: FPrefect Password: thisisn0t@dri11 1 2 setcookie:hiker=“SESSION_ID; path=/; Secure; HttpOnly; SameSite”

Slide 27

Slide 27

AUTHENTICATION HOW IT WORKS SESSION BASED AUTH { cookie:“hiker=XHTGubdsnHFJ 3 KHHJGFJHGKHhgjgJHNJGHGJHjs ddsBHJGGFJKHtcbjBUY” “id”:”89765-1”, “role”:”hitchhiker”, “email”:”ford@infinidim.com”, … 4 }

Slide 28

Slide 28

AUTHENTICATION HOW IT WORKS SESSION BASED AUTH

Slide 29

Slide 29

AUTHENTICATION HOW IT WORKS SESSION BASED AUTH

Slide 30

Slide 30

AUTHENTICATION TOKEN HOW BASED IT WORKS AUTH SESSION BASED AUTH

Slide 31

Slide 31

AUTHENTICATION HOW IT WORKS Username: FPrefect Password: thisisn0t@dri11 1 TOKEN BASED AUTH eyJhbGciOiJIUzI1NiIsInR5cCI6I kpXVCJ9.eyJuYW1lIjoiRm9yZCBQc mVmZWN0Iiwic3ViIjoiZm9yZEBpbm ZpbmlkaW0uY29tIiwiaWF0IjoxNTE 2 2MjM5MDIyLCJhcHBfbWV0YWRhdGEi OnsiYXV0aG9yaXphdGlvbiI6eyJyb 2xlcyI6WyJqb3VybmFsaXN0Il19fX 0.0eXsZauX7hjEB9oGjx7cg6LdyU8 QzNnFFS7tevWnqCA

Slide 32

Slide 32

AUTHENTICATION HOW IT WORKS Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5c CI6IkpXVCJ9.eyJuYW1lIjoiR m9yZCBQcmVmZWN0Iiwic3ViIj oiZm9yZEBpbmZpbmlkaW0uY29 tIiwiaWF0IjoxNTE2MjM5MDIy LCJhcHBfbWV0YWRhdGEiOnsiY XV0aG9yaXphdGlvbiI6eyJyb2 xlcyI6WyJqb3VybmFsaXN0Il1 9fX0.0eXsZauX7hjEB9oGjx7c g6LdyU8QzNnFFS7tevWnqCA TOKEN BASED AUTH { 3 “id”:”89765-1”, “role”:”hitchhiker”, “email”:”ford@infinidim.com”, … 4 }

Slide 33

Slide 33

JWT AUTHENTICATION HOW IT WORKS TOKEN BASED AUTH

Slide 34

Slide 34

AUTHENTICATION TOKEN BASED AUTH JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ 9.eyJuYW1lIjoiRm9yZCBQcmVmZWN0Iiwic 3ViIjoiZm9yZEBpbmZpbmlkaW0uY29tIiwi aWF0IjoxNTE2MjM5MDIyLCJhcHBfbWV0YWR hdGEiOnsiYXV0aG9yaXphdGlvbiI6eyJyb2 xlcyI6WyJqb3VybmFsaXN0Il19fX0.0eXsZ auX7hjEB9oGjx7cg6LdyU8QzNnFFS7tevWn qCA

Slide 35

Slide 35

AUTHENTICATION TOKEN BASED AUTH JWT signature payload header eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ 9.eyJuYW1lIjoiRm9yZCBQcmVmZWN0Iiwic 3ViIjoiZm9yZEBpbmZpbmlkaW0uY29tIiwi aWF0IjoxNTE2MjM5MDIyLCJhcHBfbWV0YWR hdGEiOnsiYXV0aG9yaXphdGlvbiI6eyJyb2 xlcyI6WyJqb3VybmFsaXN0Il19fX0.0eXsZ auX7hjEB9oGjx7cg6LdyU8QzNnFFS7tevWn qCA

Slide 36

Slide 36

AUTHENTICATION { } { } TOKEN BASED AUTH JWT Symmetric “alg”: “HS256”, “typ”: “JWT” “name”: “Ford Prefect”, “sub” : “ford@infinidim.com”, “exp” : “1577836800”, “app_metadata”: { “authorization”: { “roles”: [ “journalist” ] } }, header

Slide 37

Slide 37

AUTHENTICATION { } { } TOKEN BASED AUTH JWT Symmetric “alg”: “HS256”, “typ”: “JWT” “name”: “Ford Prefect”, “sub” : “ford@infinidim.com”, “exp” : “1577836800”, “app_metadata”: { “authorization”: { “roles”: [ “journalist” ] } }, header

Slide 38

Slide 38

AUTHENTICATION { } { } TOKEN BASED AUTH JWT Symmetric “alg”: “HS256”, “typ”: “JWT” “name”: “Ford Prefect”, “sub” : “ford@infinidim.com”, “exp” : “1577836800”, “app_metadata”: { “authorization”: { “roles”: [ “journalist” ] } }, header

Slide 39

Slide 39

AUTHENTICATION { } { } { TOKEN BASED AUTH JWT Symmetric “alg”: “HS256”, “typ”: “JWT” “name”: “Ford Prefect”, “sub” : “ford@infinidim.com”, “exp” : “1577836800”, “app_metadata”: { “authorization”: { “roles”: [ “journalist” ] } }, payload

Slide 40

Slide 40

“name”: “Ford Prefect”, “sub” : “ford@infinidim.com”, JWT AUTHENTICATION TOKEN BASED AUTH Symmetric “exp” : “1577836800”, “app_metadata”: { “authorization”: { “roles”: [ “journalist” ] } }, } { HMACSHA256( base64UrlEncode(header) + “.” + signature base64UrlEncode(payload), a-256-bit-super-secret-secret) }

Slide 41

Slide 41

AUTHENTICATION TOKEN BASED AUTH JWT Symmetric

Slide 42

Slide 42

AUTHENTICATION TOKEN BASED AUTH JWT

Slide 43

Slide 43

CHARACTERISTICS HISTORY HOW TOIMPLEMENTATION HAVE FUN WITH HOW TO NOT CONFUSE YOURSELF WHAT TO AVOID AUTHENTICATION TOKEN BASED AUTH

Slide 44

Slide 44

CHARACTERISTICS HISTORY HOW TO HAVE FUN WITH HOW TO NOT CONFUSE YOURSELF WHAT TO AVOID AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION

Slide 45

Slide 45

AUTHENTICATION TOKEN BASED AUTH DEMO IMPLEMENTATION

Slide 46

Slide 46

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION

Slide 47

Slide 47

AUTHENTICATION TOKEN BASED AUTH NO ADMITTANCE. NOT EVEN TO AUTHORIZED PERSONNEL. YOU ARE WASTING YOUR TIME HERE. GO AWAY. someerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsa ergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegf ywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfu wgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefw efwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDF GNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrt sjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefu wyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguw efgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfh gerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5 rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuw efwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwie fuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwe fgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfh erjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgn et6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwg efjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywe gfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefw efwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHO UWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertukt yuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwje hfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygf uywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhew erfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweu FHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwef ewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyu fgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgw uyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhker fjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsv fbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgwieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwe fuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBKsomeerfherjfhkerfjerjfhgerjfhewerfwefwefwewefwefwemhgwjefhgwefgwyefgwuyefguwefgweygfuywegfuwgefuywegfwekfgw ieyfwiefuygweyufgwuefuwyefgwjehfywegfywegfjwgefjwefwefuwefuwefwefwefewrhwrtsjertuktyuytwsaergabsgnet6ragsvfbneye5rtetqweuFHKAJDFGNWLRTHOUWTHGBK IMPLEMENTATION

Slide 48

Slide 48

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION Auth Server Username: FPrefect Password: thisisn0t@dri11 Authorization: Bearer eyJhbGciOJ9.sfsfweHsefw9 .dgergeJGhg9HV… eyJhbGciOJ9.sfsfweHsefw9 .dgergeJGhg9HV… { “id”:”89765-1”, “role”:”hitchhiker”, … } Resource Server

Slide 49

Slide 49

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION

Slide 50

Slide 50

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION Authentication with Functions as a Service |—————-| | THERE | | ARE | | STILL | | SERVERS | | IN | | SERVERLESS| |—————-| (_/) || (•ㅅ•) || / づ |—————-| | THERE | | ARE | | STILL | | SERVERS | | IN | | SERVERLESS| |—————-| (_/) || (•ㅅ•) || / づ |—————-| | THERE | | ARE | | STILL | | SERVERS | | IN | | SERVERLESS| |—————-| (_/) || (•ㅅ•) || / づ |—————-| | THERE | | ARE | | STILL | | SERVERS | | IN | | SERVERLESS| |—————-| (_/) || (•ㅅ•) || / づ

Slide 51

Slide 51

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION

Slide 52

Slide 52

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION exports.handler = function(event, context, callback) { console.log(event) callback(null, { statusCode: 200, body: JSON.stringify({ msg: “Hello, World!” }) }) } functions/jwt.js

Slide 53

Slide 53

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION MYAWESOMESITE.netlify.com/.netlify/functions/jwt

Slide 54

Slide 54

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION 56 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const jwt = require(“jsonwebtoken”); const uuidv4 = require(“uuid/v4”); const axios = require(“axios”); exports.handler = function(event, context, callback) { const getExpiryDate = () => { const exp = Math.floor(Date.now() / 1000) + 60 * 60; // const expReadable = new Date(exp); return exp; }; const generateJWT = (exp, claims, roles, secret) => jwt.sign( { exp, app_metadata: { user_id: uuidv4(), authorization: { roles } }, user_metadata: claims }, secret ); const parsedBody = JSON.parse(event.body); const { claims, roles, secret } = parsedBody;

Slide 55

Slide 55

1 const jwt = require(“jsonwebtoken”); 2 const uuidv4 = require(“uuid/v4”); IMPLEMENTATION AUTHENTICATION TOKEN BASED AUTH 3 const axios = require(“axios”); 4 5 exports.handler = function(event, context, callback) { const getExpiryDate = () => { 6 const exp = Math.floor(Date.now() / 1000) + 60 * 60; 7 // const expReadable = new Date(exp); 8 return exp; 9 }; 10 const generateJWT = (exp, claims, roles, secret) => 11 jwt.sign( 12 { 13 exp, 14 app_metadata: { 15 user_id: uuidv4(), 16 authorization: { roles } 17 }, 18 user_metadata: claims 19 }, 20 secret 21 ); 22 const parsedBody = JSON.parse(event.body); 23 const { claims, roles, secret } = parsedBody; 24 25 const expiry = getExpiryDate(); 26 const token = generateJWT(expiry, claims, roles, secret); 27 28 const response = { 29

Slide 56

Slide 56

}, 18 user_metadata: claims 19 }, 20 IMPLEMENTATION TOKEN BASED AUTH secret 21AUTHENTICATION ); 22 const parsedBody = JSON.parse(event.body); 23 const { claims, roles, secret } = parsedBody; 24 25 const expiry = getExpiryDate(); 26 const token = generateJWT(expiry, claims, roles, secret); 27 28 const response = { 29 jwt: token, 30 }; 31 32 callback(null, { 33 statusCode: 200, 34 body: JSON.stringify(response) 35 }); 36 37 }; 38 39 40 41 42 43 44 45 46 47

Slide 57

Slide 57

1 const jwt = require(“jsonwebtoken”); 2 const uuidv4 = require(“uuid/v4”); 3 const axios = require(“axios”); IMPLEMENTATION AUTHENTICATION TOKEN BASED AUTH 4 5 exports.handler = function(event, context, callback) { const getExpiryDate = () => { 6 7 // const expReadable = new Date(exp); 8 return exp; 9 }; 10 const generateJWT = (exp, claims, roles, secret) => 11 jwt.sign( 12 { 13 exp, 14 app_metadata: { 15 user_id: uuidv4(), 16 authorization: { roles } 17 }, 18 user_metadata: claims 19 }, 20 secret 21 ); 22 const parsedBody = JSON.parse(event.body); 23 const { claims, roles, secret } = parsedBody; 24 25 const expiry = getExpiryDate(); 26 const token = generateJWT(expiry, claims, roles, secret); 27 28 const response = { 29 jwt: token, 30

Slide 58

Slide 58

1 const jwt = require(“jsonwebtoken”); 2 const uuidv4 = require(“uuid/v4”); 3 const axios = require(“axios”); IMPLEMENTATION AUTHENTICATION TOKEN BASED AUTH 4 5 exports.handler = function(event, context, callback) { const getExpiryDate = () => { 6 const exp = Math.floor(Date.now() / 1000) + 60 * 60; 7 // const expReadable = new Date(exp); 8 return exp; 9 }; 10 const generateJWT = (exp, claims, roles, secret) => 11 jwt.sign( 12 { 13 exp, 14 app_metadata: { 15 user_id: uuidv4(), 16 authorization: { roles } 17 }, 18 user_metadata: claims 19 }, 20 secret 21 ); 22 const parsedBody = JSON.parse(event.body); 23 const { claims, roles, secret } = parsedBody; 24 25 const expiry = getExpiryDate(); 26 const token = generateJWT(expiry, claims, roles, secret); 27 28 const response = { 29 jwt: token, 30

Slide 59

Slide 59

}, 18 user_metadata: claims 19 }, 20 IMPLEMENTATION AUTHENTICATION TOKEN BASED AUTH secret 21 ); 22 const parsedBody = JSON.parse(event.body); 23 const { claims, roles, secret } = parsedBody; 24 25 const expiry = getExpiryDate(); 26 const token = generateJWT(expiry, claims, roles, secret); 27 28 const response = { 29 jwt: token, 30 }; 31 32 callback(null, { 33 statusCode: 200, 34 body: JSON.stringify(response) 35 }); 36 37 }; 38 39 40 41 42 43 44 45 46 47

Slide 60

Slide 60

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION 56 1 fetch(“/.netlify/functions/jwt”).then(res => { 2 fetch(“/.netlify/functions/super-secret-function”, { 3 method: “POST”, 4 headers: { 5 “Authorization”: Bearer ${res.jwt} 6 }, 7 body: JSON.stringify({ 8 text: someDataIWanttoPost 9 }) 10 }) 11 }) 12 13 14 15 16 17 18 19 20 21 22 23 24

Slide 61

Slide 61

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION Auth Server Username: FPrefect Password: thisisn0t@dri11 cookie:“hiker=XHTGubdsnH FJKHHJGFJHGKHhgjgJHNJGHG JHjsddsBHJGGFJKHtcbjBUY” setcookie:hiker=“eyJhbGciOJ 9.sfsfweHsefw9.dgergeJGh g9HV…; path=/; Secure; HttpOnly; SameSite” { “id”:”89765-1”, “role”:”hitchhiker”, … } Resource Server

Slide 62

Slide 62

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION 56 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const const const const jwt = require(“jsonwebtoken”); uuidv4 = require(“uuid/v4”); cookie = require(“cookie”); axios = require(“axios”); exports.handler = function(event, context, callback) { const getExpiryDate = () => { const exp = Math.floor(Date.now() / 1000) + 60 * 60; // const expReadable = new Date(exp); return exp; }; const generateJWT = (exp, claims, roles, secret) => jwt.sign( { exp, app_metadata: { user_id: uuidv4(), authorization: { roles } }, user_metadata: claims }, secret ); const parsedBody = JSON.parse(event.body);

Slide 63

Slide 63

secret 22 ); 23 const parsedBody = JSON.parse(event.body); 24 IMPLEMENTATION TOKEN BASED const { claims, roles, secret } = AUTH parsedBody; 25AUTHENTICATION 26 const expiry = getExpiryDate(); 27 const token = generateJWT(expiry, claims, roles, secret); 28 29 const netlifyCookie = cookie.serialize(“nf_jwt”, token, { 30 secure: true, 31 path: “/”, 32 expires: new Date(expiry.toString()) 33 }); 34 35 const response = { 36 jwt: token, 37 exp: expiry 38 }; 39 40 callback(null, { 41 statusCode: 200, 42 headers: { 43 “Set-Cookie”: netlifyCookie, 44 “Cache-Control”: “no-cache” 45 }, 46 body: JSON.stringify(response) 47 }); 48 49 }; 50 51

Slide 64

Slide 64

secret 22 ); 23 const parsedBody = JSON.parse(event.body); 24 IMPLEMENTATION TOKEN BASED const { claims, roles, secret } = AUTH parsedBody; 25AUTHENTICATION 26 const expiry = getExpiryDate(); 27 const token = generateJWT(expiry, claims, roles, secret); 28 29 const netlifyCookie = cookie.serialize(“nf_jwt”, token, { 30 secure: true, 31 path: “/”, 32 expires: new Date(expiry.toString()) 33 }); 34 35 const response = { 36 jwt: token, 37 exp: expiry 38 }; 39 40 callback(null, { 41 statusCode: 200, 42 headers: { 43 “Set-Cookie”: netlifyCookie, 44 “Cache-Control”: “no-cache” 45 }, 46 body: JSON.stringify(response) 47 }); 48 49 }; 50 51

Slide 65

Slide 65

AUTHENTICATION TOKEN BASED AUTH IMPLEMENTATION

Slide 66

Slide 66

CHARACTERISTICS HISTORY HOW TO HAVE FUN WITH OAuth + OIDC HOW TO NOT CONFUSE YOURSELF WHAT TO AVOID AUTHENTICATION

Slide 67

Slide 67

CHARACTERISTICS HISTORY HOW TO HAVE FUN WITH HOW TO NOT CONFUSE YOURSELF WHAT TO AVOID AUTHENTICATION OAuth + OIDC

Slide 68

Slide 68

AUTHENTICATION OAuth + OIDC WEB SIGN ON as P + e m a n r Use d r o sw Username + Password Redirect WEB SIGN ON

Slide 69

Slide 69

AUTHENTICATION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 OAuth + OIDC WEB SIGN ON import GoTrue from “gotrue-js”; const auth = new GoTrue({ APIUrl: “https://chipie.netlify.com/.netlify/identity”, audience: “”, setCookie: true }); function login(credentials) { return new Promise((resolve, reject) => { auth.login(credentials.email, credentials.password) .then(res => { saveState(“auth.currentUser”, res) resolve(res) }) }) } function logout() { return new Promise((resolve, reject) => { const user = auth.currentUser(); if (user) { user .logout() .then(response => {

Slide 70

Slide 70

4 APIUrl: “https://chipie.netlify.com/.netlify/identity”, 5 audience: “”, OAuth + OIDC 6AUTHENTICATION setCookie: true WEB SIGN ON 7 }); 8 9 function login(credentials) { 10 return new Promise((resolve, reject) => { 11 auth.login(credentials.email, credentials.password) 12 .then(res => { 13 saveState(“auth.currentUser”, res) 14 resolve(res) 15 }) 16 }) 17 } 18 19 function logout() { 20 return new Promise((resolve, reject) => { 21 const user = auth.currentUser(); 22 if (user) { 23 user 24 .logout() 25 .then(response => { 26 saveState(“auth.currentUser”, null) 27 resolve(“user logged out”) 28 }) 29 .catch(error => { 30 reject(error); 31 console.log(“Could not log out”, error); 32 });

Slide 71

Slide 71

32 }); 33 } else { 34AUTHENTICATION resolve(“user logged out”) OAuth + OIDC WEB SIGN ON 35 } 36 }) 37 } 38 39 function attemptSignUp(credentials) { 40 return new Promise((resolve, reject) => { 41 auth 42 .signup(credentials.email, credentials.password) 43 .then(response => { 44 resolve(response); 45 }) 46 .catch(error => { 47 reject(error); 48 }); 49 }); 50 } 51 52 function saveState(key, state) { 53 window.localStorage.setItem(key, JSON.stringify(state)); 54 } 55 56 57 58 59 60 61

Slide 72

Slide 72

AUTHENTICATION OAuth + OIDC DEMO WEB SIGN ON

Slide 73

Slide 73

AUTHENTICATION OAuth + OIDC WEB SIGN ON

Slide 74

Slide 74

AUTHENTICATION OAuthAN + OIDC CALL API CALL AN API

Slide 75

Slide 75

AUTHENTICATION OAuth + OIDC Re t s e qu CALL AN API n e k to e d o C Auth code creation Token creation h t u en A k o t e g an h c Ex es R n e k To e s n po Call API { API }

Slide 76

Slide 76

AUTHENTICATION OAuth + OIDC CALL AN API https://zoom-me-in.netlify.com https://zoom-me-in.netlify.com/.netlify/functions/google-auth Auth Code https://zoom-me-in.netlify.com/ https://zoom-me-in.netlify.com/.netlify/functions/fetch-calendar/? code=4/sQE7wyl2f06dQWv_bD9UAkXnbshrwjE6CZAGBqdAB2gbjlqYlYcy_GKzdhKuvbReX8VpTgib_FZJJMjVC0s_J4&scope=https:// www.googleapis.com/auth/calendar.readonly https://zoom-me-in.netlify.com/?token=jhgjwgeifwef

Slide 77

Slide 77

AUTHENTICATION OAuth + OIDC CALL AN API 1 // Docs on event and context https://www.netlify.com/docs/functions/#t 2 const { google } = require(“googleapis”); 3 4 exports.handler = async () => { 5 const SCOPES = [“https://www.googleapis.com/auth/calendar.readonly”] 6 let oAuth2Client, redirectURL; 7 8 try { 9 redirectURL = await authorize(); 10 } catch (e) { 11 console.log(“error”, e); 12 return { 13 statusCode: 500, 14 headers: { 15 “Access-Control-Allow-Origin”: “*”, 16 “Access-Control-Allow-Credentials”: true 17 }, 18 body: JSON.stringify({ 19 error: e.message 20 }) 21 }; 22 } 23 24 if (!redirectURL) { 25 return {

Slide 78

Slide 78

45 body: JSON.stringify({ redirectURL }) 46 }; 47 OAuth + OIDC CALL AN API 48AUTHENTICATION /** 49 * Create an OAuth2 client with the given credentials, and then exec 50 * given callback function. 51 / 52 function authorize() { 53 const { CLIENT_SECRET, CLIENT_ID, REDIRECT_URIS } = process.env; 54 oAuth2Client = new google.auth.OAuth2( 55 ${CLIENT_ID}, 56 ${CLIENT_SECRET}, 57 ${REDIRECT_URIS} 58 ); 59 return getAccessToken(oAuth2Client); 60 } 61 62 /* 63 * Get and store new token after prompting for user authorization, a 64 * execute the given callback with the authorized OAuth2 client. 65 */ 66 function getAccessToken(oAuth2Client) { 67 const authUrl = oAuth2Client.generateAuthUrl({ 68 access_type: “offline”, 69 scope: SCOPES 70 }); 71 72 return authUrl; 73 } 74 };

Slide 79

Slide 79

19 error: e.message 20 }) OAuth + OIDC CALL AN API 21AUTHENTICATION }; 22 } 23 24 if (!redirectURL) { 25 return { 26 statusCode: 200, 27 headers: { 28 “Access-Control-Allow-Origin”: “”, 29 “Access-Control-Allow-Credentials”: true 30 }, 31 body: JSON.stringify({ 32 message: “Page isn’t working!” 33 }) 34 }; 35 } 36 37 return { 38 statusCode: 200, 39 headers: { 40 “Access-Control-Allow-Origin”: “”, 41 “Access-Control-Allow-Credentials”: true, 42 “Cache-Control”: “no-cache”, 43 “Content-Type”: “text/html” 44 }, 45 body: JSON.stringify({ redirectURL }) 46 }; 47

Slide 80

Slide 80

AUTHENTICATION OAuth + OIDC CALL AN API 1 const { google } = require(“googleapis”); 2 3 exports.handler = async event => { let params = event.queryStringParameters; 4 let referer = event.headers.referer; 5 const code = params.code; 6 7 let token; 8 9 try { 10 token = await getAccessToken(code); 11 } catch (e) { 12 return { 13 statusCode: 500, 14 headers: { 15 “Access-Control-Allow-Origin”: “*”, 16 “Access-Control-Allow-Credentials”: true 17 }, 18 body: JSON.stringify({ 19 error: “I AM AN ERROR MESSAGE” 20 }) 21 }; 22 } 23 24 async function getAccessToken(code) { 25

Slide 81

Slide 81

error: “I AM AN ERROR MESSAGE” 20 }) 21 OAuth + OIDC CALL AN API }; 22AUTHENTICATION } 23 24 async function getAccessToken(code) { 25 const { CLIENT_SECRET, CLIENT_ID, REDIRECT_URIS } = process.env; 26 27 let oAuth2Client = new google.auth.OAuth2( 28 ${CLIENT_ID}, 29 ${CLIENT_SECRET}, 30 ${REDIRECT_URIS} 31 ); 32 33 try { 34 let accessToken = await oAuth2Client.getToken(code); 35 // await oAuth2Client.setCredentials(token.tokens); 36 return accessToken; 37 } catch (e) { 38 return console.error(“Error retrieving access token”, e); 39 } 40 } 41 42 return { 43 statusCode: 302, 44 headers: { 45 “Access-Control-Allow-Origin”: “*”, 46 “Access-Control-Allow-Credentials”: true, 47 “Cache-Control”: “no-cache”, 48

Slide 82

Slide 82

async function getAccessToken(code) { 25 const { CLIENT_SECRET, CLIENT_ID, REDIRECT_URIS } = process.env; 26 27AUTHENTICATION OAuth + OIDC CALL AN API let oAuth2Client = new google.auth.OAuth2( 28 ${CLIENT_ID}, 29 ${CLIENT_SECRET}, 30 ${REDIRECT_URIS} 31 ); 32 33 try { 34 let accessToken = await oAuth2Client.getToken(code); 35 // await oAuth2Client.setCredentials(token.tokens); 36 return accessToken; 37 } catch (e) { 38 return console.error(“Error retrieving access token”, e); 39 } 40 } 41 42 return { 43 statusCode: 302, 44 headers: { 45 “Access-Control-Allow-Origin”: “*”, 46 “Access-Control-Allow-Credentials”: true, 47 “Cache-Control”: “no-cache”, 48 Location: ${referer}?token=${token.tokens.access_token} 49 }, 50 body: JSON.stringify({ event: token.tokens.access_token }) 51 }; 52 53 }; 54

Slide 83

Slide 83

AUTHENTICATION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 OAuth + OIDC CALL AN API if (window.location.search.indexOf(“token”) > -1) { this.token = this.geturlparams(“token”); this.getCalendarEvents(); } function geturlparams(name) { // courtesy of https://stackoverflow.com/a/5158301/3216524 // var match = RegExp(“[?&]” + name + “=([^&]*)”).exec( window.location.search ); return match && decodeURIComponent(match[1].replace(/+/g, ” “)); } function getCalendarEvents() { // https://www.googleapis.com/calendar/v3/calendars/primary/events? key={YOUR_API_KEY} var start = new Date(); start.setHours(0, 0, 0, 0); var end = new Date(); end.setHours(23, 59, 59, 999); axios .get( https://www.googleapis.com/calendar/v3/calendars/primary/events? singleEvents=true&timeMax=${end.toISOString()}&timeMin=$ {start.toISOString()}&orderBy=startTime,

Slide 84

Slide 84

AUTHENTICATION 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 OAuth + OIDC CALL AN API if (window.location.search.indexOf(“token”) > -1) { this.token = this.geturlparams(“token”); this.getCalendarEvents(); } function geturlparams(name) { // courtesy of https://stackoverflow.com/a/5158301/3216524 // var match = RegExp(“[?&]” + name + “=([^&]*)”).exec( window.location.search ); return match && decodeURIComponent(match[1].replace(/+/g, ” “)); } function getCalendarEvents() { // https://www.googleapis.com/calendar/v3/calendars/primary/events? key={YOUR_API_KEY} var start = new Date(); start.setHours(0, 0, 0, 0); var end = new Date(); end.setHours(23, 59, 59, 999); axios .get( https://www.googleapis.com/calendar/v3/calendars/primary/events? singleEvents=true&timeMax=${end.toISOString()}&timeMin=$ {start.toISOString()}&orderBy=startTime,

Slide 85

Slide 85

var match = RegExp(“[?&]” + name + “=([^&]*)”).exec( 9 window.location.search 10 ); OAuth + OIDC CALL AN API ” “)); 11AUTHENTICATION return match && decodeURIComponent(match[1].replace(/+/g, 12 } 13 14 function getCalendarEvents() { 15 // https://www.googleapis.com/calendar/v3/calendars/primary/events? 16 key={YOUR_API_KEY} 17 var start = new Date(); 18 start.setHours(0, 0, 0, 0); 19 var end = new Date(); 20 end.setHours(23, 59, 59, 999); 21 axios 22 .get( 23 https://www.googleapis.com/calendar/v3/calendars/primary/events? 24 singleEvents=true&timeMax=${end.toISOString()}&timeMin=$ 25 {start.toISOString()}&orderBy=startTime, 26 { 27 headers: { 28 Authorization: Bearer ${this.token} 29 } 30 } 31 ) 32 .then(res => { 33 console.log(res.data.items); 34 this.owner = res.data.summary.split(“@”)[0]; 35 this.events = res.data.items; 36 }); 37 }

Slide 86

Slide 86

AUTHENTICATION OAuth + OIDC DEMO CALL AN API

Slide 87

Slide 87

AUTHENTICATION OAuth + OIDC CALL AN API

Slide 88

Slide 88

AUTHENTICATION OAuth + OIDC CALL AN API

Slide 89

Slide 89

AUTHENTICATION OAuth + OIDC CALL AN API

Slide 90

Slide 90

AUTHENTICATION DON’T ROLL YOUR OWN Resource Server JWT OAuth Authentication Server OpenID Connect

Slide 91

Slide 91

AUTHENTICATION LINKS AND THINGS Roll your own JWT code: https://github.com/shortdiv/jwt-generate example: https://login-to-gated-site.netlify.com/ Sign in Example code: https://github.com/shortdiv/planet-express-deliveryportal/ Call an API Example code: https://github.com/shortdiv/zoom-me-in OAuth + OIDC Resources: https://auth0.com/docs/videos/learn-identity

Slide 92

Slide 92

So Long and Thanks for All the Auth!!! Divya Sasidharan @shortdiv