From a3cb5fed2b46d7064c1dc7242ecd453edd96dde1 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 12 Feb 2020 17:27:19 -0500 Subject: [PATCH 01/18] Added basic layout with login page --- examples/with-passport/components/header.js | 53 ++++++++++++++ examples/with-passport/components/layout.js | 39 ++++++++++ examples/with-passport/package.json | 16 ++++ examples/with-passport/pages/index.js | 29 ++++++++ examples/with-passport/pages/login.js | 81 +++++++++++++++++++++ 5 files changed, 218 insertions(+) create mode 100644 examples/with-passport/components/header.js create mode 100644 examples/with-passport/components/layout.js create mode 100644 examples/with-passport/package.json create mode 100644 examples/with-passport/pages/index.js create mode 100644 examples/with-passport/pages/login.js diff --git a/examples/with-passport/components/header.js b/examples/with-passport/components/header.js new file mode 100644 index 000000000000000..9ff77acf659729c --- /dev/null +++ b/examples/with-passport/components/header.js @@ -0,0 +1,53 @@ +import Link from 'next/link' + +const Header = () => ( +
+ + +
+) + +export default Header diff --git a/examples/with-passport/components/layout.js b/examples/with-passport/components/layout.js new file mode 100644 index 000000000000000..4178067a4128c80 --- /dev/null +++ b/examples/with-passport/components/layout.js @@ -0,0 +1,39 @@ +import Head from 'next/head' +import Header from './header' + +const Layout = props => ( + <> + + With Cookies + + +
+ +
+
{props.children}
+
+ + + +) + +export default Layout diff --git a/examples/with-passport/package.json b/examples/with-passport/package.json new file mode 100644 index 000000000000000..e3d267adfa5b5bd --- /dev/null +++ b/examples/with-passport/package.json @@ -0,0 +1,16 @@ +{ + "name": "with-passport", + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "js-cookie": "latest", + "next": "latest", + "next-cookies": "latest", + "react": "latest", + "react-dom": "latest" + }, + "license": "ISC" +} diff --git a/examples/with-passport/pages/index.js b/examples/with-passport/pages/index.js new file mode 100644 index 000000000000000..dc4bfb40e3d45d3 --- /dev/null +++ b/examples/with-passport/pages/index.js @@ -0,0 +1,29 @@ +import React from 'react' +import Layout from '../components/layout' + +const Home = () => ( + +

Passport.js Example

+ +

Steps to test the example:

+ +
    +
  1. Click login and enter an username and password.
  2. +
  3. + Click home and click profile again, notice how your session is being + used through a token stored in a cookie. +
  4. +
  5. + Click logout and try to go to profile again. You'll get redirected to + the `/login` route. +
  6. +
+ +
+) + +export default Home diff --git a/examples/with-passport/pages/login.js b/examples/with-passport/pages/login.js new file mode 100644 index 000000000000000..7e495929fa382f8 --- /dev/null +++ b/examples/with-passport/pages/login.js @@ -0,0 +1,81 @@ +import { useState } from 'react' +import Layout from '../components/layout' + +const Login = () => { + const [errorMsg, setErrorMsg] = useState('') + + async function handleSubmit(e) { + event.preventDefault() + + if (errorMsg) setErrorMsg('') + + const username = e.currentTarget.username.value + + try { + const response = await fetch('/api/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username }), + }) + if (response.status === 200) { + // const { token } = await response.json() + // await login({ token }) + } else { + throw new Error(response.statusText) + } + } catch (error) { + console.error('An unexpected error happened occurred:', error) + setErrorMsg(error.message) + } + } + + return ( + +
+
+ + + + + + {errorMsg &&

Error: {errorMsg}

} +
+
+ +
+ ) +} + +export default Login From e46a5ea306302f0599d14b32817eae2914564ca0 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 12 Feb 2020 18:10:32 -0500 Subject: [PATCH 02/18] Updated styles --- examples/with-passport/components/header.js | 15 ++++++++++- examples/with-passport/components/layout.js | 7 +++-- examples/with-passport/pages/login.js | 29 ++++++++++++++++----- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/examples/with-passport/components/header.js b/examples/with-passport/components/header.js index 9ff77acf659729c..00ba3be8bbc6696 100644 --- a/examples/with-passport/components/header.js +++ b/examples/with-passport/components/header.js @@ -25,6 +25,11 @@ const Header = () => (
) diff --git a/examples/with-passport/components/layout.js b/examples/with-passport/components/layout.js index 4178067a4128c80..174351ec9b608d4 100644 --- a/examples/with-passport/components/layout.js +++ b/examples/with-passport/components/layout.js @@ -27,10 +27,9 @@ const Layout = props => ( 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; } .container { - max-width: 65rem; - margin: 1.5rem auto; - padding-left: 1rem; - padding-right: 1rem; + max-width: 42rem; + margin: 0 auto; + padding: 2rem 1.25rem; } `} diff --git a/examples/with-passport/pages/login.js b/examples/with-passport/pages/login.js index 7e495929fa382f8..bc5994cd6e4f3f3 100644 --- a/examples/with-passport/pages/login.js +++ b/examples/with-passport/pages/login.js @@ -41,15 +41,15 @@ const Login = () => { Password - - - - {errorMsg &&

Error: {errorMsg}

} +
+ {errorMsg &&

{errorMsg}

} + +
From 91af4b281c91df7bad0340415efb5d084cfa87e3 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 12 Feb 2020 18:29:18 -0500 Subject: [PATCH 03/18] Added form component --- examples/with-passport/components/form.js | 76 +++++++++++++++++++++++ examples/with-passport/pages/login.js | 58 +++-------------- 2 files changed, 83 insertions(+), 51 deletions(-) create mode 100644 examples/with-passport/components/form.js diff --git a/examples/with-passport/components/form.js b/examples/with-passport/components/form.js new file mode 100644 index 000000000000000..552cd78be914716 --- /dev/null +++ b/examples/with-passport/components/form.js @@ -0,0 +1,76 @@ +import Link from 'next/link' + +const Form = ({ isLogin, errorMessage, onSubmit }) => ( +
+ + + +
+ {isLogin ? ( + <> + + I don't have an account + + + + ) : ( + <> + + I already have an account + + + + )} +
+ + {errorMessage &&

{errorMessage}

} + + +
+) + +export default Form diff --git a/examples/with-passport/pages/login.js b/examples/with-passport/pages/login.js index bc5994cd6e4f3f3..b71198790808529 100644 --- a/examples/with-passport/pages/login.js +++ b/examples/with-passport/pages/login.js @@ -1,5 +1,6 @@ import { useState } from 'react' import Layout from '../components/layout' +import Form from '../components/form' const Login = () => { const [errorMsg, setErrorMsg] = useState('') @@ -9,13 +10,16 @@ const Login = () => { if (errorMsg) setErrorMsg('') - const username = e.currentTarget.username.value + const body = { + username: e.currentTarget.username.value, + password: e.currentTarget.password.value, + } try { const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ username }), + body: JSON.stringify(body), }) if (response.status === 200) { // const { token } = await response.json() @@ -32,20 +36,7 @@ const Login = () => { return (
-
- - -
- {errorMsg &&

{errorMsg}

} - -
-
+
) From 3ac46ab03d5db21fdb065ef703bb7874f6a0d3ef Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 12 Feb 2020 18:31:40 -0500 Subject: [PATCH 04/18] Added signup page --- examples/with-passport/pages/signup.js | 54 ++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 examples/with-passport/pages/signup.js diff --git a/examples/with-passport/pages/signup.js b/examples/with-passport/pages/signup.js new file mode 100644 index 000000000000000..f830311ef2f5b87 --- /dev/null +++ b/examples/with-passport/pages/signup.js @@ -0,0 +1,54 @@ +import { useState } from 'react' +import Layout from '../components/layout' +import Form from '../components/form' + +const Signup = () => { + const [errorMsg, setErrorMsg] = useState('') + + async function handleSubmit(e) { + event.preventDefault() + + if (errorMsg) setErrorMsg('') + + const body = { + username: e.currentTarget.username.value, + password: e.currentTarget.password.value, + } + + try { + const response = await fetch('/api/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }) + if (response.status === 200) { + // const { token } = await response.json() + // await login({ token }) + } else { + throw new Error(response.statusText) + } + } catch (error) { + console.error('An unexpected error happened occurred:', error) + setErrorMsg(error.message) + } + } + + return ( + +
+ +
+ +
+ ) +} + +export default Signup From 5dcfa5d87eaecb6575138a9e1d3ab5c151249819 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 15:14:27 -0500 Subject: [PATCH 05/18] Added login/signup API endpoints --- examples/with-passport/lib/configs.js | 2 ++ examples/with-passport/lib/password-login.js | 24 +++++++++++++++++ examples/with-passport/lib/user.js | 27 ++++++++++++++++++++ examples/with-passport/package.json | 4 +++ examples/with-passport/pages/api/login.js | 21 +++++++++++++++ examples/with-passport/pages/api/signup.js | 10 ++++++++ examples/with-passport/pages/signup.js | 2 +- 7 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 examples/with-passport/lib/configs.js create mode 100644 examples/with-passport/lib/password-login.js create mode 100644 examples/with-passport/lib/user.js create mode 100644 examples/with-passport/pages/api/login.js create mode 100644 examples/with-passport/pages/api/signup.js diff --git a/examples/with-passport/lib/configs.js b/examples/with-passport/lib/configs.js new file mode 100644 index 000000000000000..2f4189cfb97439e --- /dev/null +++ b/examples/with-passport/lib/configs.js @@ -0,0 +1,2 @@ +// Use an environment variable here instead of a hardcoded value in a production environment +export const TOKEN_SECRET = 'this-is-a-secret-value' diff --git a/examples/with-passport/lib/password-login.js b/examples/with-passport/lib/password-login.js new file mode 100644 index 000000000000000..63f6ea33d3bfba8 --- /dev/null +++ b/examples/with-passport/lib/password-login.js @@ -0,0 +1,24 @@ +import Local from 'passport-local' +import Iron from '@hapi/iron' +import { TOKEN_SECRET } from './configs' +import { findUser } from './user' + +export const localStrategy = new Local.Strategy(function( + username, + password, + done +) { + findUser({ username, password }) + .then(user => { + return { ...user, createdAt: Date.now() } + }) + .then(session => { + return Iron.seal(session, TOKEN_SECRET, Iron.defaults) + }) + .then(encryptedToken => { + done(null, encryptedToken) + }) + .catch(() => { + done(null, false, { message: 'Invalid user' }) + }) +}) diff --git a/examples/with-passport/lib/user.js b/examples/with-passport/lib/user.js new file mode 100644 index 000000000000000..713877c272440d0 --- /dev/null +++ b/examples/with-passport/lib/user.js @@ -0,0 +1,27 @@ +// import crypto from 'crypto' + +/** + * User methods. The example doesn't contain a DB, but for real applications you must use a + * db here, like Mongodb, Fauna, SQL, e.t.c + */ + +export async function createUser({ username, password }) { + // Here you should create the user and save the salt and hashed password (some dbs may have + // authentication methods that will do it for you so you don't have to worry about it): + // + // const salt = crypto.randomBytes(16).toString('hex') + // const hash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex') + // const user = await DB.createUser({ username, salt, hash }) + + return { username } +} + +export async function findUser({ username, password }) { + // Here you should lookup for the user in your DB and compare the password: + // + // const user = await DB.findUser(...) + // const hash = crypto.pbkdf2Sync(password, user.salt, 1000, 64, 'sha512').toString('hex') + // const passwordsMatch = user.hash === hash + + return { username } +} diff --git a/examples/with-passport/package.json b/examples/with-passport/package.json index e3d267adfa5b5bd..ad7e1f84ddfbbdc 100644 --- a/examples/with-passport/package.json +++ b/examples/with-passport/package.json @@ -6,9 +6,13 @@ "start": "next start" }, "dependencies": { + "@hapi/iron": "6.0.0", + "express": "4.17.1", "js-cookie": "latest", "next": "latest", "next-cookies": "latest", + "passport": "0.4.1", + "passport-local": "1.0.0", "react": "latest", "react-dom": "latest" }, diff --git a/examples/with-passport/pages/api/login.js b/examples/with-passport/pages/api/login.js new file mode 100644 index 000000000000000..bc075928f7ac950 --- /dev/null +++ b/examples/with-passport/pages/api/login.js @@ -0,0 +1,21 @@ +import express from 'express' +import passport from 'passport' +import { loginStrategy } from '../../lib/password-login' + +const app = express() + +app.disable('x-powered-by') + +app.use(passport.initialize()) + +passport.use(loginStrategy) + +app.post('/api/login', (req, res) => { + // callbackURL is not in the options for the GitHub strategy, but it can be used + passport.authenticate('local', { session: false }, (token, info) => { + console.log('TOKEN', token, info) + res.status(200).send({ done: true }) + })(req, res) +}) + +export default app diff --git a/examples/with-passport/pages/api/signup.js b/examples/with-passport/pages/api/signup.js new file mode 100644 index 000000000000000..9f3bf4196793cca --- /dev/null +++ b/examples/with-passport/pages/api/signup.js @@ -0,0 +1,10 @@ +import createUser from '../../lib/user' + +export default async function signup(req, res) { + try { + await createUser(req.body) + res.status(200).send({ done: true }) + } catch (error) { + res.status(500).end(error.message) + } +} diff --git a/examples/with-passport/pages/signup.js b/examples/with-passport/pages/signup.js index f830311ef2f5b87..34aa4b576cfd1db 100644 --- a/examples/with-passport/pages/signup.js +++ b/examples/with-passport/pages/signup.js @@ -16,7 +16,7 @@ const Signup = () => { } try { - const response = await fetch('/api/login', { + const response = await fetch('/api/signup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), From 475605b0532a19d0fb23a160a9599ce31a1ebfc5 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 15:46:29 -0500 Subject: [PATCH 06/18] Bug fixes --- examples/with-passport/lib/configs.js | 2 +- examples/with-passport/lib/password-login.js | 4 +-- examples/with-passport/pages/api/login.js | 28 +++++++++++++++----- examples/with-passport/pages/api/signup.js | 1 + examples/with-passport/pages/login.js | 6 ++--- examples/with-passport/pages/signup.js | 6 ++--- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/examples/with-passport/lib/configs.js b/examples/with-passport/lib/configs.js index 2f4189cfb97439e..252cef4075a9bd3 100644 --- a/examples/with-passport/lib/configs.js +++ b/examples/with-passport/lib/configs.js @@ -1,2 +1,2 @@ // Use an environment variable here instead of a hardcoded value in a production environment -export const TOKEN_SECRET = 'this-is-a-secret-value' +export const TOKEN_SECRET = 'this-is-a-secret-value-with-at-least-32-characters' diff --git a/examples/with-passport/lib/password-login.js b/examples/with-passport/lib/password-login.js index 63f6ea33d3bfba8..1a1b11d365a2641 100644 --- a/examples/with-passport/lib/password-login.js +++ b/examples/with-passport/lib/password-login.js @@ -18,7 +18,7 @@ export const localStrategy = new Local.Strategy(function( .then(encryptedToken => { done(null, encryptedToken) }) - .catch(() => { - done(null, false, { message: 'Invalid user' }) + .catch(error => { + done(error) }) }) diff --git a/examples/with-passport/pages/api/login.js b/examples/with-passport/pages/api/login.js index bc075928f7ac950..5072a1e07514022 100644 --- a/examples/with-passport/pages/api/login.js +++ b/examples/with-passport/pages/api/login.js @@ -1,21 +1,35 @@ import express from 'express' import passport from 'passport' -import { loginStrategy } from '../../lib/password-login' +import { localStrategy } from '../../lib/password-login' const app = express() +const authenticate = (method, req, res) => + new Promise((resolve, reject) => { + passport.authenticate(method, { session: false }, (error, token) => { + if (error) { + reject(error) + } else { + resolve(token) + } + })(req, res) + }) + app.disable('x-powered-by') app.use(passport.initialize()) -passport.use(loginStrategy) +passport.use(localStrategy) -app.post('/api/login', (req, res) => { - // callbackURL is not in the options for the GitHub strategy, but it can be used - passport.authenticate('local', { session: false }, (token, info) => { - console.log('TOKEN', token, info) +app.post('/api/login', async (req, res) => { + try { + const token = await authenticate('local', req, res) + console.log(token) res.status(200).send({ done: true }) - })(req, res) + } catch (error) { + console.error(error) + res.status(401).send(error.message) + } }) export default app diff --git a/examples/with-passport/pages/api/signup.js b/examples/with-passport/pages/api/signup.js index 9f3bf4196793cca..6cf2f74324d9fe9 100644 --- a/examples/with-passport/pages/api/signup.js +++ b/examples/with-passport/pages/api/signup.js @@ -5,6 +5,7 @@ export default async function signup(req, res) { await createUser(req.body) res.status(200).send({ done: true }) } catch (error) { + console.error(error) res.status(500).end(error.message) } } diff --git a/examples/with-passport/pages/login.js b/examples/with-passport/pages/login.js index b71198790808529..5f432d5c7d9cf2d 100644 --- a/examples/with-passport/pages/login.js +++ b/examples/with-passport/pages/login.js @@ -16,16 +16,16 @@ const Login = () => { } try { - const response = await fetch('/api/login', { + const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) - if (response.status === 200) { + if (res.status === 200) { // const { token } = await response.json() // await login({ token }) } else { - throw new Error(response.statusText) + throw new Error(await res.text()) } } catch (error) { console.error('An unexpected error happened occurred:', error) diff --git a/examples/with-passport/pages/signup.js b/examples/with-passport/pages/signup.js index 34aa4b576cfd1db..174b125476fe0b9 100644 --- a/examples/with-passport/pages/signup.js +++ b/examples/with-passport/pages/signup.js @@ -16,16 +16,16 @@ const Signup = () => { } try { - const response = await fetch('/api/signup', { + const res = await fetch('/api/signup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }) - if (response.status === 200) { + if (res.status === 200) { // const { token } = await response.json() // await login({ token }) } else { - throw new Error(response.statusText) + throw new Error(await res.text()) } } catch (error) { console.error('An unexpected error happened occurred:', error) From 87cd1c0dde211bc8537c6a9072a93c9d9cd360ee Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 16:08:05 -0500 Subject: [PATCH 07/18] Set the cookie --- examples/with-passport/package.json | 1 + examples/with-passport/pages/api/login.js | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/examples/with-passport/package.json b/examples/with-passport/package.json index ad7e1f84ddfbbdc..550ab5415e1e925 100644 --- a/examples/with-passport/package.json +++ b/examples/with-passport/package.json @@ -7,6 +7,7 @@ }, "dependencies": { "@hapi/iron": "6.0.0", + "cookie": "0.4.0", "express": "4.17.1", "js-cookie": "latest", "next": "latest", diff --git a/examples/with-passport/pages/api/login.js b/examples/with-passport/pages/api/login.js index 5072a1e07514022..14a6eeaf9866cc0 100644 --- a/examples/with-passport/pages/api/login.js +++ b/examples/with-passport/pages/api/login.js @@ -1,5 +1,6 @@ import express from 'express' import passport from 'passport' +import { serialize } from 'cookie' import { localStrategy } from '../../lib/password-login' const app = express() @@ -24,7 +25,17 @@ passport.use(localStrategy) app.post('/api/login', async (req, res) => { try { const token = await authenticate('local', req, res) - console.log(token) + const maxAge = 60 * 60 * 8 // 8 hours + const cookie = serialize('token', token, { + maxAge, + expires: new Date(Date.now() + maxAge * 1000), + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + path: '/', + sameSite: 'lax', + }) + + res.setHeader('Set-Cookie', cookie) res.status(200).send({ done: true }) } catch (error) { console.error(error) From cdb7d75c18a86f052a1cb0bc0b04cbd9c4e5e741 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 16:13:59 -0500 Subject: [PATCH 08/18] Added logout route --- examples/with-passport/pages/api/logout.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 examples/with-passport/pages/api/logout.js diff --git a/examples/with-passport/pages/api/logout.js b/examples/with-passport/pages/api/logout.js new file mode 100644 index 000000000000000..a82c76ce81d6570 --- /dev/null +++ b/examples/with-passport/pages/api/logout.js @@ -0,0 +1,12 @@ +import { serialize } from 'cookie' + +export default async function logout(req, res) { + const cookie = serialize('token', '', { + maxAge: -1, + path: '/', + }) + + res.setHeader('Set-Cookie', cookie) + res.writeHead(302, { Location: '/' }) + res.end() +} From 67ba222427209ce7fc9558166c34326df4c72cb3 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 16:49:59 -0500 Subject: [PATCH 09/18] Added more auth --- examples/with-passport/lib/auth-cookies.js | 40 ++++++++++++++++++++ examples/with-passport/lib/auth.js | 16 ++++++++ examples/with-passport/lib/configs.js | 2 - examples/with-passport/lib/password-login.js | 10 +---- examples/with-passport/lib/user.js | 4 +- examples/with-passport/pages/api/login.js | 21 ++++------ examples/with-passport/pages/api/logout.js | 9 +---- examples/with-passport/pages/api/user.js | 9 +++++ 8 files changed, 78 insertions(+), 33 deletions(-) create mode 100644 examples/with-passport/lib/auth-cookies.js create mode 100644 examples/with-passport/lib/auth.js delete mode 100644 examples/with-passport/lib/configs.js create mode 100644 examples/with-passport/pages/api/user.js diff --git a/examples/with-passport/lib/auth-cookies.js b/examples/with-passport/lib/auth-cookies.js new file mode 100644 index 000000000000000..1d215f3a664239b --- /dev/null +++ b/examples/with-passport/lib/auth-cookies.js @@ -0,0 +1,40 @@ +import { serialize, parse } from 'cookie' + +const TOKEN_NAME = 'token' +const MAX_AGE = 60 * 60 * 8 // 8 hours + +export function setTokenCookie(res, token) { + const cookie = serialize(TOKEN_NAME, token, { + maxAge: MAX_AGE, + expires: new Date(Date.now() + MAX_AGE * 1000), + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + path: '/', + sameSite: 'lax', + }) + + res.setHeader('Set-Cookie', cookie) +} + +export function removeTokenCookie(res) { + const cookie = serialize(TOKEN_NAME, '', { + maxAge: -1, + path: '/', + }) + + res.setHeader('Set-Cookie', cookie) +} + +export function parseCookies(req) { + // For API Routes we don't need to parse the cookies. + if (req.cookies) return req.cookies + + // For pages we do need to parse the cookies. + const cookie = req.headers?.cookie + return parse(cookie || '') +} + +export function getTokenCookie(req) { + const cookies = parseCookies(req) + return cookies[TOKEN_NAME] +} diff --git a/examples/with-passport/lib/auth.js b/examples/with-passport/lib/auth.js new file mode 100644 index 000000000000000..f2f3b42bef5d231 --- /dev/null +++ b/examples/with-passport/lib/auth.js @@ -0,0 +1,16 @@ +import Iron from '@hapi/iron' +import { getTokenCookie } from './auth-cookies' + +// Use an environment variable here instead of a hardcoded value in a production environment +const TOKEN_SECRET = 'this-is-a-secret-value-with-at-least-32-characters' + +export function encryptSession(session) { + return Iron.seal(session, TOKEN_SECRET, Iron.defaults) +} + +export async function getSession(req) { + const token = getTokenCookie(req) + const session = await Iron.unseal(token, TOKEN_SECRET, Iron.defaults) + + return Iron.unseal(session, TOKEN_SECRET, Iron.defaults) +} diff --git a/examples/with-passport/lib/configs.js b/examples/with-passport/lib/configs.js deleted file mode 100644 index 252cef4075a9bd3..000000000000000 --- a/examples/with-passport/lib/configs.js +++ /dev/null @@ -1,2 +0,0 @@ -// Use an environment variable here instead of a hardcoded value in a production environment -export const TOKEN_SECRET = 'this-is-a-secret-value-with-at-least-32-characters' diff --git a/examples/with-passport/lib/password-login.js b/examples/with-passport/lib/password-login.js index 1a1b11d365a2641..1fc07d7d447813d 100644 --- a/examples/with-passport/lib/password-login.js +++ b/examples/with-passport/lib/password-login.js @@ -1,6 +1,4 @@ import Local from 'passport-local' -import Iron from '@hapi/iron' -import { TOKEN_SECRET } from './configs' import { findUser } from './user' export const localStrategy = new Local.Strategy(function( @@ -10,13 +8,7 @@ export const localStrategy = new Local.Strategy(function( ) { findUser({ username, password }) .then(user => { - return { ...user, createdAt: Date.now() } - }) - .then(session => { - return Iron.seal(session, TOKEN_SECRET, Iron.defaults) - }) - .then(encryptedToken => { - done(null, encryptedToken) + done(null, user) }) .catch(error => { done(error) diff --git a/examples/with-passport/lib/user.js b/examples/with-passport/lib/user.js index 713877c272440d0..c31ecbeda46958f 100644 --- a/examples/with-passport/lib/user.js +++ b/examples/with-passport/lib/user.js @@ -13,7 +13,7 @@ export async function createUser({ username, password }) { // const hash = crypto.pbkdf2Sync(password, salt, 1000, 64, 'sha512').toString('hex') // const user = await DB.createUser({ username, salt, hash }) - return { username } + return { username, createdAt: Date.now() } } export async function findUser({ username, password }) { @@ -23,5 +23,5 @@ export async function findUser({ username, password }) { // const hash = crypto.pbkdf2Sync(password, user.salt, 1000, 64, 'sha512').toString('hex') // const passwordsMatch = user.hash === hash - return { username } + return { username, createdAt: Date.now() } } diff --git a/examples/with-passport/pages/api/login.js b/examples/with-passport/pages/api/login.js index 14a6eeaf9866cc0..856a020c588fe1d 100644 --- a/examples/with-passport/pages/api/login.js +++ b/examples/with-passport/pages/api/login.js @@ -1,10 +1,10 @@ import express from 'express' import passport from 'passport' -import { serialize } from 'cookie' import { localStrategy } from '../../lib/password-login' +import { encryptSession } from '../../lib/auth' +import { setTokenCookie } from '../../lib/auth-cookies' const app = express() - const authenticate = (method, req, res) => new Promise((resolve, reject) => { passport.authenticate(method, { session: false }, (error, token) => { @@ -24,18 +24,13 @@ passport.use(localStrategy) app.post('/api/login', async (req, res) => { try { - const token = await authenticate('local', req, res) - const maxAge = 60 * 60 * 8 // 8 hours - const cookie = serialize('token', token, { - maxAge, - expires: new Date(Date.now() + maxAge * 1000), - httpOnly: true, - secure: process.env.NODE_ENV === 'production', - path: '/', - sameSite: 'lax', - }) + const user = await authenticate('local', req, res) + // session is the payload to save in the token, it may contain basic info about the user + const session = { ...user } + // The token is a string with the encrypted session + const token = await encryptSession(session) - res.setHeader('Set-Cookie', cookie) + setTokenCookie(res, token) res.status(200).send({ done: true }) } catch (error) { console.error(error) diff --git a/examples/with-passport/pages/api/logout.js b/examples/with-passport/pages/api/logout.js index a82c76ce81d6570..1fe3096cdc014e1 100644 --- a/examples/with-passport/pages/api/logout.js +++ b/examples/with-passport/pages/api/logout.js @@ -1,12 +1,7 @@ -import { serialize } from 'cookie' +import { removeTokenCookie } from '../../lib/auth-cookies' export default async function logout(req, res) { - const cookie = serialize('token', '', { - maxAge: -1, - path: '/', - }) - - res.setHeader('Set-Cookie', cookie) + removeTokenCookie(res) res.writeHead(302, { Location: '/' }) res.end() } diff --git a/examples/with-passport/pages/api/user.js b/examples/with-passport/pages/api/user.js new file mode 100644 index 000000000000000..9a1de329b2a2f57 --- /dev/null +++ b/examples/with-passport/pages/api/user.js @@ -0,0 +1,9 @@ +import { getSession } from '../../lib/auth' + +export default async function user(req, res) { + const session = getSession(req) + // After getting the session you may want to fetch for the user instead + // of sending the session's payload directly, this example doesn't have a DB + // so it won't matter in this case + res.status(200).json({ user: session }) +} From c8efcef13d3117426707320556bcb5c76fc13522 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 17:12:30 -0500 Subject: [PATCH 10/18] Updated signup --- examples/with-passport/components/form.js | 6 ++++++ examples/with-passport/pages/api/signup.js | 2 +- examples/with-passport/pages/signup.js | 9 +++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/examples/with-passport/components/form.js b/examples/with-passport/components/form.js index 552cd78be914716..2b5ba4b9f04e9d1 100644 --- a/examples/with-passport/components/form.js +++ b/examples/with-passport/components/form.js @@ -10,6 +10,12 @@ const Form = ({ isLogin, errorMessage, onSubmit }) => ( Password + {!isLogin && ( + + )}
{isLogin ? ( diff --git a/examples/with-passport/pages/api/signup.js b/examples/with-passport/pages/api/signup.js index 6cf2f74324d9fe9..7972d47838a74b9 100644 --- a/examples/with-passport/pages/api/signup.js +++ b/examples/with-passport/pages/api/signup.js @@ -1,4 +1,4 @@ -import createUser from '../../lib/user' +import { createUser } from '../../lib/user' export default async function signup(req, res) { try { diff --git a/examples/with-passport/pages/signup.js b/examples/with-passport/pages/signup.js index 174b125476fe0b9..23d443f2b23dcb0 100644 --- a/examples/with-passport/pages/signup.js +++ b/examples/with-passport/pages/signup.js @@ -1,4 +1,5 @@ import { useState } from 'react' +import Router from 'next/router' import Layout from '../components/layout' import Form from '../components/form' @@ -15,6 +16,11 @@ const Signup = () => { password: e.currentTarget.password.value, } + if (body.password !== e.currentTarget.rpassword.value) { + setErrorMsg(`The passwords don't match`) + return + } + try { const res = await fetch('/api/signup', { method: 'POST', @@ -22,8 +28,7 @@ const Signup = () => { body: JSON.stringify(body), }) if (res.status === 200) { - // const { token } = await response.json() - // await login({ token }) + Router.push('/login') } else { throw new Error(await res.text()) } From 22f5fbeb80705cbecd3af2befd183daddbbb306d Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 17:17:53 -0500 Subject: [PATCH 11/18] Added profile page --- examples/with-passport/pages/login.js | 4 ++-- examples/with-passport/pages/profile.js | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 examples/with-passport/pages/profile.js diff --git a/examples/with-passport/pages/login.js b/examples/with-passport/pages/login.js index 5f432d5c7d9cf2d..b974896712cae1c 100644 --- a/examples/with-passport/pages/login.js +++ b/examples/with-passport/pages/login.js @@ -1,4 +1,5 @@ import { useState } from 'react' +import Router from 'next/router' import Layout from '../components/layout' import Form from '../components/form' @@ -22,8 +23,7 @@ const Login = () => { body: JSON.stringify(body), }) if (res.status === 200) { - // const { token } = await response.json() - // await login({ token }) + Router.push('/profile') } else { throw new Error(await res.text()) } diff --git a/examples/with-passport/pages/profile.js b/examples/with-passport/pages/profile.js new file mode 100644 index 000000000000000..0054901c60584b6 --- /dev/null +++ b/examples/with-passport/pages/profile.js @@ -0,0 +1,10 @@ +import Layout from '../components/layout' + +const Home = () => ( + +

Profile

+

Your session: {JSON.stringify({ yo: 'yay' })}

+
+) + +export default Home From 20e970490c01234079be4be8fb778ca268b0f367 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 19:31:14 -0500 Subject: [PATCH 12/18] Added useUser --- examples/with-passport/components/header.js | 13 ++--- examples/with-passport/lib/auth.js | 4 +- examples/with-passport/lib/hooks.js | 31 ++++++++++++ examples/with-passport/package.json | 3 +- examples/with-passport/pages/api/user.js | 4 +- examples/with-passport/pages/index.js | 53 ++++++++++++--------- examples/with-passport/pages/login.js | 3 ++ examples/with-passport/pages/profile.js | 19 +++++--- examples/with-passport/pages/signup.js | 3 ++ 9 files changed, 87 insertions(+), 46 deletions(-) create mode 100644 examples/with-passport/lib/hooks.js diff --git a/examples/with-passport/components/header.js b/examples/with-passport/components/header.js index 00ba3be8bbc6696..8599cab00a8dca9 100644 --- a/examples/with-passport/components/header.js +++ b/examples/with-passport/components/header.js @@ -20,7 +20,9 @@ const Header = () => (
  • - + + Logout +
  • @@ -50,15 +52,6 @@ const Header = () => ( color: #fff; background-color: #333; } - button { - color: #fff; - font-size: 1rem; - font-family: inherit; - cursor: pointer; - background: none; - border: none; - padding: 0; - } `} ) diff --git a/examples/with-passport/lib/auth.js b/examples/with-passport/lib/auth.js index f2f3b42bef5d231..6a2fc39b93b4c46 100644 --- a/examples/with-passport/lib/auth.js +++ b/examples/with-passport/lib/auth.js @@ -10,7 +10,5 @@ export function encryptSession(session) { export async function getSession(req) { const token = getTokenCookie(req) - const session = await Iron.unseal(token, TOKEN_SECRET, Iron.defaults) - - return Iron.unseal(session, TOKEN_SECRET, Iron.defaults) + return token && Iron.unseal(token, TOKEN_SECRET, Iron.defaults) } diff --git a/examples/with-passport/lib/hooks.js b/examples/with-passport/lib/hooks.js new file mode 100644 index 000000000000000..645364466d3c06d --- /dev/null +++ b/examples/with-passport/lib/hooks.js @@ -0,0 +1,31 @@ +import { useEffect } from 'react' +import Router from 'next/router' +import useSWR from 'swr' + +const fetcher = url => + fetch(url) + .then(r => r.json()) + .then(data => { + return { user: data?.user || null } + }) + +export function useUser({ redirectTo, redirectIfFound } = {}) { + const { data, error } = useSWR('/api/user', fetcher) + const user = data?.user + const finished = Boolean(data) + const hasUser = Boolean(user) + + useEffect(() => { + if (!redirectTo || !finished) return + if ( + // If redirectTo is set, redirect if the user was not found. + (redirectTo && !redirectIfFound && !hasUser) || + // If redirectIfFound is also set, redirect if the user was found + (redirectIfFound && hasUser) + ) { + Router.push(redirectTo) + } + }, [redirectTo, redirectIfFound, finished, hasUser]) + + return error ? null : user +} diff --git a/examples/with-passport/package.json b/examples/with-passport/package.json index 550ab5415e1e925..efbcb48bd1e788d 100644 --- a/examples/with-passport/package.json +++ b/examples/with-passport/package.json @@ -15,7 +15,8 @@ "passport": "0.4.1", "passport-local": "1.0.0", "react": "latest", - "react-dom": "latest" + "react-dom": "latest", + "swr": "0.1.16" }, "license": "ISC" } diff --git a/examples/with-passport/pages/api/user.js b/examples/with-passport/pages/api/user.js index 9a1de329b2a2f57..b5cb9612afecf46 100644 --- a/examples/with-passport/pages/api/user.js +++ b/examples/with-passport/pages/api/user.js @@ -1,9 +1,9 @@ import { getSession } from '../../lib/auth' export default async function user(req, res) { - const session = getSession(req) + const session = await getSession(req) // After getting the session you may want to fetch for the user instead // of sending the session's payload directly, this example doesn't have a DB // so it won't matter in this case - res.status(200).json({ user: session }) + res.status(200).json({ user: session || null }) } diff --git a/examples/with-passport/pages/index.js b/examples/with-passport/pages/index.js index dc4bfb40e3d45d3..77d90c75d240cda 100644 --- a/examples/with-passport/pages/index.js +++ b/examples/with-passport/pages/index.js @@ -1,29 +1,36 @@ -import React from 'react' +import { useUser } from '../lib/hooks' import Layout from '../components/layout' -const Home = () => ( - -

    Passport.js Example

    +const Home = () => { + const user = useUser() -

    Steps to test the example:

    + return ( + +

    Passport.js Example

    -
      -
    1. Click login and enter an username and password.
    2. -
    3. - Click home and click profile again, notice how your session is being - used through a token stored in a cookie. -
    4. -
    5. - Click logout and try to go to profile again. You'll get redirected to - the `/login` route. -
    6. -
    - -
    -) +

    Steps to test the example:

    + +
      +
    1. Click login and enter an username and password.
    2. +
    3. + Click home and click profile again, notice how your session is being + used through a token stored in a cookie. +
    4. +
    5. + Click logout and try to go to profile again. You'll get redirected to + the `/login` route. +
    6. +
    + + {user &&

    Currently logged in as: {JSON.stringify(user)}

    } + + +
    + ) +} export default Home diff --git a/examples/with-passport/pages/login.js b/examples/with-passport/pages/login.js index b974896712cae1c..8cd75ee29f1172b 100644 --- a/examples/with-passport/pages/login.js +++ b/examples/with-passport/pages/login.js @@ -1,9 +1,12 @@ import { useState } from 'react' import Router from 'next/router' +import { useUser } from '../lib/hooks' import Layout from '../components/layout' import Form from '../components/form' const Login = () => { + useUser({ redirectTo: '/', redirectIfFound: true }) + const [errorMsg, setErrorMsg] = useState('') async function handleSubmit(e) { diff --git a/examples/with-passport/pages/profile.js b/examples/with-passport/pages/profile.js index 0054901c60584b6..9a263b4983fa01a 100644 --- a/examples/with-passport/pages/profile.js +++ b/examples/with-passport/pages/profile.js @@ -1,10 +1,15 @@ +import { useUser } from '../lib/hooks' import Layout from '../components/layout' -const Home = () => ( - -

    Profile

    -

    Your session: {JSON.stringify({ yo: 'yay' })}

    -
    -) +const Profile = () => { + const user = useUser({ redirectTo: '/' }) -export default Home + return ( + +

    Profile

    + {user &&

    Your session: {JSON.stringify(user)}

    } +
    + ) +} + +export default Profile diff --git a/examples/with-passport/pages/signup.js b/examples/with-passport/pages/signup.js index 23d443f2b23dcb0..a0f31880a8ff6b0 100644 --- a/examples/with-passport/pages/signup.js +++ b/examples/with-passport/pages/signup.js @@ -1,9 +1,12 @@ import { useState } from 'react' import Router from 'next/router' +import { useUser } from '../lib/hooks' import Layout from '../components/layout' import Form from '../components/form' const Signup = () => { + useUser({ redirectTo: '/', redirectIfFound: true }) + const [errorMsg, setErrorMsg] = useState('') async function handleSubmit(e) { From 954f6bbf36bbf16d480d7eae0124e5d100b96119 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 19:32:25 -0500 Subject: [PATCH 13/18] Fix link --- examples/with-passport/components/header.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/with-passport/components/header.js b/examples/with-passport/components/header.js index 8599cab00a8dca9..51280c6cfff8fa2 100644 --- a/examples/with-passport/components/header.js +++ b/examples/with-passport/components/header.js @@ -20,9 +20,7 @@ const Header = () => (
  • - - Logout - + Logout
  • From ab6737373ca48780a9687554a11e886bde1986b6 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 19:37:41 -0500 Subject: [PATCH 14/18] Updated redirect path --- examples/with-passport/pages/index.js | 10 +++++----- examples/with-passport/pages/profile.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/with-passport/pages/index.js b/examples/with-passport/pages/index.js index 77d90c75d240cda..0870d849e3d8cda 100644 --- a/examples/with-passport/pages/index.js +++ b/examples/with-passport/pages/index.js @@ -11,14 +11,14 @@ const Home = () => {

    Steps to test the example:

      -
    1. Click login and enter an username and password.
    2. +
    3. Click Login and enter an username and password.
    4. - Click home and click profile again, notice how your session is being - used through a token stored in a cookie. + You'll be redirected to Home. Click on Profile, notice how your + session is being used through a token stored in a cookie.
    5. - Click logout and try to go to profile again. You'll get redirected to - the `/login` route. + Click Logout and try to go to Profile again. You'll get redirected to + Login.
    diff --git a/examples/with-passport/pages/profile.js b/examples/with-passport/pages/profile.js index 9a263b4983fa01a..e864f7480f04b0a 100644 --- a/examples/with-passport/pages/profile.js +++ b/examples/with-passport/pages/profile.js @@ -2,7 +2,7 @@ import { useUser } from '../lib/hooks' import Layout from '../components/layout' const Profile = () => { - const user = useUser({ redirectTo: '/' }) + const user = useUser({ redirectTo: '/login' }) return ( From 9a42f60007bdc6db3afb8572d494069bd7ddd01e Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 19:53:28 -0500 Subject: [PATCH 15/18] Renaming some files --- examples/with-passport/lib/{auth.js => iron.js} | 2 +- .../lib/{password-login.js => password-local.js} | 0 examples/with-passport/pages/api/login.js | 4 ++-- examples/with-passport/pages/api/user.js | 2 +- examples/with-passport/pages/login.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename examples/with-passport/lib/{auth.js => iron.js} (94%) rename examples/with-passport/lib/{password-login.js => password-local.js} (100%) diff --git a/examples/with-passport/lib/auth.js b/examples/with-passport/lib/iron.js similarity index 94% rename from examples/with-passport/lib/auth.js rename to examples/with-passport/lib/iron.js index 6a2fc39b93b4c46..977c4b110dd9946 100644 --- a/examples/with-passport/lib/auth.js +++ b/examples/with-passport/lib/iron.js @@ -1,7 +1,7 @@ import Iron from '@hapi/iron' import { getTokenCookie } from './auth-cookies' -// Use an environment variable here instead of a hardcoded value in a production environment +// Use an environment variable here instead of a hardcoded value for production const TOKEN_SECRET = 'this-is-a-secret-value-with-at-least-32-characters' export function encryptSession(session) { diff --git a/examples/with-passport/lib/password-login.js b/examples/with-passport/lib/password-local.js similarity index 100% rename from examples/with-passport/lib/password-login.js rename to examples/with-passport/lib/password-local.js diff --git a/examples/with-passport/pages/api/login.js b/examples/with-passport/pages/api/login.js index 856a020c588fe1d..62fb8be02f20441 100644 --- a/examples/with-passport/pages/api/login.js +++ b/examples/with-passport/pages/api/login.js @@ -1,7 +1,7 @@ import express from 'express' import passport from 'passport' -import { localStrategy } from '../../lib/password-login' -import { encryptSession } from '../../lib/auth' +import { localStrategy } from '../../lib/password-local' +import { encryptSession } from '../../lib/iron' import { setTokenCookie } from '../../lib/auth-cookies' const app = express() diff --git a/examples/with-passport/pages/api/user.js b/examples/with-passport/pages/api/user.js index b5cb9612afecf46..dad216c76e9a30c 100644 --- a/examples/with-passport/pages/api/user.js +++ b/examples/with-passport/pages/api/user.js @@ -1,4 +1,4 @@ -import { getSession } from '../../lib/auth' +import { getSession } from '../../lib/iron' export default async function user(req, res) { const session = await getSession(req) diff --git a/examples/with-passport/pages/login.js b/examples/with-passport/pages/login.js index 8cd75ee29f1172b..64ccd37f4355813 100644 --- a/examples/with-passport/pages/login.js +++ b/examples/with-passport/pages/login.js @@ -26,7 +26,7 @@ const Login = () => { body: JSON.stringify(body), }) if (res.status === 200) { - Router.push('/profile') + Router.push('/') } else { throw new Error(await res.text()) } From 7d80698754b57b11ed0e94c1658e67d2a5e563f4 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Thu, 13 Feb 2020 21:48:01 -0500 Subject: [PATCH 16/18] Added README --- examples/with-passport/README.md | 48 +++++++++++++++++++++++++++++ examples/with-passport/package.json | 2 -- 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 examples/with-passport/README.md diff --git a/examples/with-passport/README.md b/examples/with-passport/README.md new file mode 100644 index 000000000000000..2e1259e1fe84dad --- /dev/null +++ b/examples/with-passport/README.md @@ -0,0 +1,48 @@ +# Passport.js Example + +This example show how to use [Passport.js](http://www.passportjs.org) with Next.js. The example features cookie based authentication with username and password. + +The example shows how to do a login, signup and logout; and to get the user info using a hook with [SWR](https://swr.now.sh). + +A DB is not included, you can use any db you want and add it [here](/lib/user.js). + +The login cookie is httpOnly, meaning it can only be accessed by the API, and it's encrypted using [@hapi/iron](https://hapi.dev/family/iron) for more security. + +## Deploy your own + +Deploy the example using [ZEIT Now](https://zeit.co/now): + +[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/next.js/tree/canary/examples/with-passport) + +## How to use + +### Using `create-next-app` + +Execute [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npm init next-app --example with-passport with-passport-app +# or +yarn create next-app --example with-passport with-passport-app +``` + +### Download manually + +Download the example [or clone the repo](https://github.com/zeit/next.js): + +```bash +curl https://codeload.github.com/zeit/next.js/tar.gz/canary | tar -xz --strip=2 next.js-canary/examples/with-passport +cd with-passport +``` + +Install it and run: + +```bash +npm install +npm run dev +# or +yarn +yarn dev +``` + +Deploy it to the cloud with [ZEIT Now](https://zeit.co/new?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-passport/package.json b/examples/with-passport/package.json index efbcb48bd1e788d..5c15d1ca55a64c6 100644 --- a/examples/with-passport/package.json +++ b/examples/with-passport/package.json @@ -9,9 +9,7 @@ "@hapi/iron": "6.0.0", "cookie": "0.4.0", "express": "4.17.1", - "js-cookie": "latest", "next": "latest", - "next-cookies": "latest", "passport": "0.4.1", "passport-local": "1.0.0", "react": "latest", From 5fe1f1c3ab71356f27b641dd6fb1de232d7fe5a1 Mon Sep 17 00:00:00 2001 From: Luis Alvarez D Date: Tue, 3 Mar 2020 14:16:56 -0500 Subject: [PATCH 17/18] Apply suggestions from Shu Co-Authored-By: Shu Uesugi --- examples/with-passport/README.md | 4 ++-- examples/with-passport/lib/user.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/with-passport/README.md b/examples/with-passport/README.md index 2e1259e1fe84dad..db78f88011dfd4d 100644 --- a/examples/with-passport/README.md +++ b/examples/with-passport/README.md @@ -4,7 +4,7 @@ This example show how to use [Passport.js](http://www.passportjs.org) with Next. The example shows how to do a login, signup and logout; and to get the user info using a hook with [SWR](https://swr.now.sh). -A DB is not included, you can use any db you want and add it [here](/lib/user.js). +A DB is not included. You can use any db you want and add it [here](/lib/user.js). The login cookie is httpOnly, meaning it can only be accessed by the API, and it's encrypted using [@hapi/iron](https://hapi.dev/family/iron) for more security. @@ -45,4 +45,4 @@ yarn yarn dev ``` -Deploy it to the cloud with [ZEIT Now](https://zeit.co/new?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). +Deploy it to the cloud with [ZEIT Now](https://zeit.co/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-passport/lib/user.js b/examples/with-passport/lib/user.js index c31ecbeda46958f..80276dabd035e90 100644 --- a/examples/with-passport/lib/user.js +++ b/examples/with-passport/lib/user.js @@ -2,7 +2,7 @@ /** * User methods. The example doesn't contain a DB, but for real applications you must use a - * db here, like Mongodb, Fauna, SQL, e.t.c + * db here, such as MongoDB, Fauna, SQL, etc. */ export async function createUser({ username, password }) { From 5e5eae27e39e212c962747e42f0269d0011ec80a Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 18 Mar 2020 12:22:50 -0500 Subject: [PATCH 18/18] Add useUser to the header --- examples/with-passport/components/header.js | 116 +++++++++++--------- 1 file changed, 63 insertions(+), 53 deletions(-) diff --git a/examples/with-passport/components/header.js b/examples/with-passport/components/header.js index 51280c6cfff8fa2..0b605d656739a8d 100644 --- a/examples/with-passport/components/header.js +++ b/examples/with-passport/components/header.js @@ -1,57 +1,67 @@ import Link from 'next/link' +import { useUser } from '../lib/hooks' -const Header = () => ( -
    - - -
    -) +const Header = () => { + const user = useUser() + + return ( +
    + + +
    + ) +} export default Header