Serverless Authentication Strategies with Netlify Identity

A presentation at Serverless Chicago + Chicago NodeJS (April 2019) in April 2019 in Chicago, IL, USA by Divya

Slide 1

Slide 1

Serverless Auth Strategies with Netlify Identity Divya Sasidharan @shortdiv

Slide 2

Slide 2

Why Authentication?

Slide 3

Slide 3

Slide 4

Slide 4

What is Authentication?

Slide 5

Slide 5

Login ??? Log Out Logged In

Slide 6

Slide 6

Slide 7

Slide 7

Slide 8

Slide 8

SSO MFA Silent Auth Social Login Passwordless

Slide 9

Slide 9

https://www.netlify.com/blog/ 2018/11/28/authentication-for-therest-of-us/

Slide 10

Slide 10

Netlify Identity

Slide 11

Slide 11

Slide 12

Slide 12

Slide 13

Slide 13

Slide 14

Slide 14

Slide 15

Slide 15

Slide 16

Slide 16

<script type=”text/javascript” src=”https://identity.netlify.com/v1/ netlify-identity-widget.js”></script>

Slide 17

Slide 17

yarn add netlify-identity-widget

Slide 18

Slide 18

const netlifyIdentity = require(‘netlify-identity-widget’); netlifyIdentity.open(); const user = netlifyIdentity.currentUser(); netlifyIdentity.on(‘init’, user => { console.log(‘init’, user) }); netlifyIdentity.on(‘login’, user => { console.log(‘login’, user) }); netlifyIdentity.on(‘logout’, user => { console.log(‘logout’) }); netlifyIdentity.close();

Slide 19

Slide 19

const netlifyIdentity = require(‘netlify-identity-widget’); netlifyIdentity.open(); const user = netlifyIdentity.currentUser(); netlifyIdentity.on(‘init’, user => { console.log(‘init’, user) }); netlifyIdentity.on(‘login’, user => { console.log(‘login’, user) }); netlifyIdentity.on(‘logout’, user => { console.log(‘logout’) }); netlifyIdentity.close();

Slide 20

Slide 20

const netlifyIdentity = require(‘netlify-identity-widget’); netlifyIdentity.open(); const user = netlifyIdentity.currentUser(); netlifyIdentity.on(‘init’, user => { console.log(‘init’, user) }); netlifyIdentity.on(‘login’, user => { console.log(‘login’, user) }); netlifyIdentity.on(‘logout’, user => { console.log(‘logout’) }); netlifyIdentity.close();

Slide 21

Slide 21

const netlifyIdentity = require(‘netlify-identity-widget’); netlifyIdentity.open(); const user = netlifyIdentity.currentUser(); netlifyIdentity.on(‘init’, user => { console.log(‘init’, user) }); netlifyIdentity.on(‘login’, user => { console.log(‘login’, user) }); netlifyIdentity.on(‘logout’, user => { console.log(‘logout’) }); netlifyIdentity.close();

Slide 22

Slide 22

const netlifyIdentity = require(‘netlify-identity-widget’); netlifyIdentity.open(); const user = netlifyIdentity.currentUser(); netlifyIdentity.on(‘init’, user => { console.log(‘init’, user) }); netlifyIdentity.on(‘login’, user => { console.log(‘login’, user) }); netlifyIdentity.on(‘logout’, user => { console.log(‘logout’) }); netlifyIdentity.close();

Slide 23

Slide 23

Demo Time!

Slide 24

Slide 24

MUCH FUN SUCH FUNCTIONS

Slide 25

Slide 25

Slide 26

Slide 26

export function handler(event, context, callback) { console.log(event) callback(null, { statusCode: 200, body: JSON.stringify({msg: “Hello, World!”}) }) } src/lambda/hello.js

Slide 27

Slide 27

[build] command = “yarn build” functions = “lambda” publish = “dist” netlify.toml

Slide 28

Slide 28

Slide 29

Slide 29

/.netlify/functions/{function_name}

Slide 30

Slide 30

/.netlify/functions/login

Slide 31

Slide 31

Custom Webhooks API Call

Slide 32

Slide 32

Slide 33

Slide 33

Custom Webhooks API Call

Slide 34

Slide 34

netlifyIdentity.on(‘signup’, user => { axios({ url: /.identity/functions/login, method: “GET” }) });

Slide 35

Slide 35

netlifyIdentity.on(‘signup’, user => { axios({ url: /.identity/functions/login, method: “GET” }) });

Slide 36

Slide 36

Custom Webhooks API Call Automagic web hooks

Slide 37

Slide 37

validate signup login

Slide 38

Slide 38

export function handler(event, context, callback) { console.log(event) callback(null, { statusCode: 200, body: JSON.stringify({msg: “Hello, World!”}) }) } src/lambda/identity-login.js

Slide 39

Slide 39

exports.handler = function(event, context, callback) { const {identity, user} = context.clientContext; // do some stuff // callback(null, { statusCode: 200, body: JSON.stringify({ msg: “hello”}) }); };

Slide 40

Slide 40

exports.handler = function(event, context, callback) { const {identity, user} = context.clientContext; // do some stuff // callback(null, { statusCode: 200, body: JSON.stringify({ msg: “hello”}) }); };

Slide 41

Slide 41

exports.handler = function(event, context, callback) { const {identity, user} = context.clientContext; // do some stuff // callback(null, { statusCode: 200, body: JSON.stringify({ msg: “hello”}) }); };

Slide 42

Slide 42

Slide 43

Slide 43

exports.handler = function(event, context, callback) { const data = JSON.parse(event.body); const { user } = data; console.log(user.email); console.log(“identity yourself”, context.clientContext.identity); const validateUser = email => { if (email.split(“@”)[1] === “netlify.com”) { return [“editor”]; } else { return [“visitor”]; } }; const roles = validateUser(user.email); const responseBody = { app_metadata: { roles, my_user_info: “this is user info that the user can’t change from the UI” }, user_metadata: { …user.user_metadata, custom_data_from_function: “hurray this is some extra metadata” } }; }; callback(null, { statusCode: 200, body: JSON.stringify(responseBody) });

Slide 44

Slide 44

exports.handler = function(event, context, callback) { const data = JSON.parse(event.body); const { user } = data; console.log(user.email); console.log(“identity yourself”, context.clientContext.identity); const validateUser = email => { if (email.split(“@”)[1] === “netlify.com”) { return [“editor”]; } else { return [“visitor”]; } }; const roles = validateUser(user.email); const responseBody = { app_metadata: { roles, my_user_info: “this is user info that the user can’t change from the UI” }, user_metadata: { …user.user_metadata, custom_data_from_function: “hurray this is some extra metadata” } }; }; callback(null, { statusCode: 200, body: JSON.stringify(responseBody) });

Slide 45

Slide 45

exports.handler = function(event, context, callback) { const data = JSON.parse(event.body); const { user } = data; console.log(user.email); console.log(“identity yourself”, context.clientContext.identity); const validateUser = email => { if (email.split(“@”)[1] === “netlify.com”) { return [“editor”]; } else { return [“visitor”]; } }; const roles = validateUser(user.email); const responseBody = { app_metadata: { roles, my_user_info: “this is user info that the user can’t change from the UI” }, user_metadata: { …user.user_metadata, custom_data_from_function: “hurray this is some extra metadata” } }; }; callback(null, { statusCode: 200, body: JSON.stringify(responseBody) });

Slide 46

Slide 46

exports.handler = function(event, context, callback) { const data = JSON.parse(event.body); const { user } = data; console.log(user.email); console.log(“identity yourself”, context.clientContext.identity); const validateUser = email => { if (email.split(“@”)[1] === “netlify.com”) { return [“editor”]; } else { return [“visitor”]; } }; const roles = validateUser(user.email); const responseBody = { app_metadata: { roles, my_user_info: “this is user info that the user can’t change from the UI” }, user_metadata: { …user.user_metadata, custom_data_from_function: “hurray this is some extra metadata” } }; }; callback(null, { statusCode: 200, body: JSON.stringify(responseBody) });

Slide 47

Slide 47

exports.handler = function(event, context, callback) { const data = JSON.parse(event.body); const { user } = data; console.log(user.email); console.log(“identity yourself”, context.clientContext.identity); const validateUser = email => { if (email.split(“@”)[1] === “netlify.com”) { return [“editor”]; } else { return [“visitor”]; } }; const roles = validateUser(user.email); const responseBody = { app_metadata: { roles, my_user_info: “this is user info that the user can’t change from the UI” }, user_metadata: { …user.user_metadata, custom_data_from_function: “hurray this is some extra metadata” } }; }; callback(null, { statusCode: 200, body: JSON.stringify(responseBody) });

Slide 48

Slide 48

{ }; app_metadata: { roles, …user.app_metadata, my_user_info: “some user info” }, user_metadata: { …user.user_metadata, custom_data_from_function: “hurray extra metadata!” }

Slide 49

Slide 49

{ }; app_metadata: { roles, …user.app_metadata, my_user_info: “some user info” }, user_metadata: { …user.user_metadata, custom_data_from_function: “hurray extra metadata!” }

Slide 50

Slide 50

Demo Time!

Slide 51

Slide 51

What about local development?

Slide 52

Slide 52

Netlify Identity

Slide 53

Slide 53

GoTrue An SWT based API for managing users and issuing SWT tokens GoTrueJS

Slide 54

Slide 54

Slide 55

Slide 55

import GoTrue from “gotrue-js”; export const auth = new GoTrue({ APIUrl: “https://auth-to-know.com/.netlify/identity”, audience: “”, setCookie: false });

Slide 56

Slide 56

const attemptLogin = ({ commit, dispatch }, creds) => { return new Promise((resolve, reject) => { auth .login(creds.email, creds.password) .then(response => { resolve(response); commit(“SET_CURRENT_USER”, response); }) .catch(error => { reject(error.json); }); }); };

Slide 57

Slide 57

https://www.netlify.com/blog/ 2018/12/07/gotrue-js—-bringingauthentication-to-static-sites-withjust-3kb-of-js/

Slide 58

Slide 58

! serverless chicago https://noti.st/shortdiv Divya Sasidharan @shortdiv