13 | This is the about page, navigating between this page and Home is
14 | always pretty fast. However, when you navigate to the Profile page it takes more time because it uses SSR to
15 | fetch the user first;
16 |
25 | Once you have logged in you should be able to click in Profile and Logout
26 |
27 | >
28 | )}
29 |
30 | {user && (
31 | <>
32 |
Rendered user info on the client
33 |
{JSON.stringify(user, null, 2)}
34 | >
35 | )}
36 |
37 | )
38 | };
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # Distribution directories
61 | dist/
62 |
63 | # Next.js
64 | .next
65 |
--------------------------------------------------------------------------------
/lib/user.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import fetch from 'isomorphic-unfetch';
3 |
4 | // Use a global to save the user, so we don't have to fetch it again after page navigations
5 | let userState;
6 |
7 | const User = React.createContext({ user: null, loading: false });
8 |
9 | export const fetchUser = async () => {
10 | if (userState !== undefined) {
11 | return userState;
12 | }
13 |
14 | const res = await fetch('/api/me');
15 | userState = res.ok ? await res.json() : null;
16 | return userState;
17 | }
18 |
19 | export const UserProvider = ({ value, children }) => {
20 | const { user } = value;
21 |
22 | // If the user was fetched in SSR add it to userState so we don't fetch it again
23 | React.useEffect(() => {
24 | if (!userState && user) {
25 | userState = user
26 | }
27 | }, []);
28 |
29 | return {children};
30 | }
31 |
32 | export const useUser = () => React.useContext(User);
33 |
34 | export const useFetchUser = () => {
35 | const [data, setUser] = React.useState({
36 | user: userState || null,
37 | loading: userState === undefined
38 | });
39 |
40 | React.useEffect(() => {
41 | if (userState !== undefined) {
42 | return;
43 | }
44 |
45 | let isMounted = true;
46 |
47 | fetchUser().then(user => {
48 | // Only set the user if the component is still mounted
49 | if (isMounted) {
50 | setUser({ user, loading: false });
51 | }
52 | })
53 |
54 | return () => {
55 | isMounted = false
56 | };
57 | }, [userState]);
58 |
59 | return data;
60 | }
61 |
--------------------------------------------------------------------------------
/components/header.js:
--------------------------------------------------------------------------------
1 | import Link from 'next/link';
2 |
3 | import { useUser } from '../lib/user';
4 |
5 | const Header = () => {
6 | const { user, loading } = useUser();
7 |
8 | return (
9 |
10 |
51 |
52 |
86 |
87 | )
88 | }
89 |
90 | export default Header;
91 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Next.js and Auth0 Example
2 |
3 | This example shows how you can use [`@auth0/nextjs-auth0`](https://github.com/auth0/nextjs-auth0) to easily add authentication support to your Next.js application.
4 |
5 | ## Configuring Auth0
6 |
7 | Go to the [Auth0 dashboard](https://manage.auth0.com/) and create a new application of type *Web Application* and make sure to configure the following:
8 |
9 | - *Allowed Callback URLs*: Should be set to `http://localhost:3000/api/callback` when testing locally or typically to `https://myapp.com/api/callback` when deploying your application.
10 | - *Allowed Logout URLs*: Should be set to `http://localhost:3000/` when testing locally or typically to `https://myapp.com/` when deploying your application.
11 |
12 | ### Configuring Next.js
13 |
14 | In the Next.js configuration file (`next.config.js`) you'll see that different environment variables are being loaded in the server runtime configuration.
15 |
16 | ### Local Development
17 |
18 | For local development you'll just want to create a `.env` file with the necessary settings:
19 |
20 | ```
21 | AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
22 | AUTH0_CLIENT_ID=YOUR_AUTH0_CLIENT_ID
23 | AUTH0_CLIENT_SECRET=YOUR_AUTH0_CLIENT_SECRET
24 | REDIRECT_URI=http://localhost:3000/api/callback
25 | POST_LOGOUT_REDIRECT_URI=http://localhost:3000/
26 | SESSION_COOKIE_SECRET=viloxyf_z2GW6K4CT-KQD_MoLEA2wqv5jWuq4Jd0P7ymgG5GJGMpvMneXZzhK3sL (at least 32 characters, used to encrypt the cookie)
27 | ```
28 |
29 | ### Hosting in Now.sh
30 |
31 | When deploying this example to Now.sh you'll want to update the `now.json` configuration file:
32 |
33 | ```json
34 | {
35 | "build": {
36 | "env": {
37 | "AUTH0_DOMAIN": "YOUR_AUTH0_DOMAIN",
38 | "AUTH0_CLIENT_ID": "YOUR_AUTH0_CLIENT_ID",
39 | "AUTH0_CLIENT_SECRET": "@auth0_client_secret",
40 | "REDIRECT_URI": "https://my-website.now.sh/api/callback",
41 | "POST_LOGOUT_REDIRECT_URI": "https://my-website.now.sh/",
42 | "SESSION_COOKIE_SECRET": "@session_cookie_secret",
43 | "SESSION_COOKIE_LIFETIME": 7200
44 | }
45 | }
46 | }
47 | ```
48 |
49 | Some of these values are settings and can just be added to your repository if you want. Others are actual secrets and need to be created as such using the `now` CLI:
50 |
51 | ```bash
52 | now secrets add auth0_client_secret YOUR_AUTH0_CLIENT_SECRET
53 | now secrets add session_cookie_secret viloxyf_z2GW6K4CT-KQD_MoLEA2wqv5jWuq4Jd0P7ymgG5GJGMpvMneXZzhK3sL
54 | ```
55 |
56 | ## About this sample
57 |
58 | This sample tries to cover a few topics:
59 |
60 | - Signing in
61 | - Signing out
62 | - Registration
63 | - Loading the user on the server side and adding it as part of SSR (`/pages/profile.js`)
64 | - Loading the user on the client side and using fast/cached SSR pages (`/pages/index.js`)
65 | - API Routes which can load the current user (`/pages/api/me.js`)
66 | - Using hooks to make the user available throughout the application (`/lib//user.js`)
67 |
68 | ## Scenarios
69 |
70 | ### User Registration
71 |
72 | When the user is not signed in you'll see a Register and a Login link:
73 |
74 | ```js
75 |
81 | ```
82 |
83 | The Register link redirects to the `/api/register` API route calling the login handler and passing a custom parameter which sets `prompt=signup`.
84 |
85 | ```js
86 | import auth0 from '../../lib/auth0';
87 |
88 | export default async function register(req, res) {
89 | try {
90 | await auth0.handleLogin(req, res, {
91 | authParams: {
92 | initialScreen: 'signup'
93 | }
94 | });
95 | } catch(error) {
96 | console.error(error)
97 | res.status(error.status || 500).end(error.message)
98 | }
99 | }
100 | ```
101 |
102 | This parameter is then exposed to the Auth0 login page which can be used to show the signup tab. Note that this only works for the "Classic" experience today. In order to change to the signup tab when this parameter is sent, you'll need to modify the Login page in Auth0 and add the `initialScreen`:
103 |
104 | ```js
105 | var lock = new Auth0Lock(config.clientID, config.auth0Domain, {
106 | ...
107 | initialScreen: (config.extraParams.initialScreen === 'signup' && 'signUp') || 'login',
108 | ...
109 | });
110 | ```
--------------------------------------------------------------------------------