End to End React with Prisma 2

Start at the beginning and work your way through this project. The code for each step as well as the finished project can be found in the Github repository.


    3. Configure Auth0

    Objective: Let's set up Auth0 so we have a way to verify who is making the request so we can tell if they have access to or not.

    Create an account with Auth0 and then create a new single page application. Go to settings and copy the Domain, Client ID, Client Secret to the following environmental variables in the .env file in the project root (not the prisma folder).

    .env

    DATABASE_URL=postgresql://user:password@endpoint:5432/database_name
    AUTH0_CLIENTID=your_auth0_client_id
    AUTH0_DOMAIN=your_auth0_domain
    AUTH0_CLIENT_SECRET=your_auth0_client_secret
    AUTH0_SCOPE='openid profile'
    AUTH0_COOKIE_SECRET='some_greater_than_40_character_string_can_be_anything'
    BACKEND_ADDRESS=http://localhost:3000

    Install the Auth0 Nextjs package:

    npm install --save @auth0/nextjs-auth0 dotenv @apollo/client graphql

    utils/apolloClient.ts

    ts

    import { useMemo } from 'react'
    import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client'
    import getConfig from 'next/config'
    const { publicRuntimeConfig } = getConfig()
    const { BACKEND_URL } = publicRuntimeConfig
    let apolloClient
    function createApolloClient() {
    return new ApolloClient({
    ssrMode: typeof window === 'undefined',
    link: new HttpLink({
    uri: BACKEND_URL, // Server URL (must be absolute)
    credentials: 'same-origin', // Additional fetch() options like `credentials` or `headers`
    }),
    cache: new InMemoryCache({}),
    })
    }
    export function initializeApollo(initialState = null) {
    const _apolloClient = apolloClient ?? createApolloClient()
    // If your page has Next.js data fetching methods that use Apollo Client, the initial state
    // gets hydrated here
    if (initialState) {
    // Get existing cache, loaded during client side data fetching
    const existingCache = _apolloClient.extract()
    // Restore the cache using the data passed from getStaticProps/getServerSideProps
    // combined with the existing cached data
    _apolloClient.cache.restore({ ...existingCache, ...initialState })
    }
    // For SSG and SSR always create a new Apollo Client
    if (typeof window === 'undefined') return _apolloClient
    // Create the Apollo Client once in the client
    if (!apolloClient) apolloClient = _apolloClient
    return _apolloClient
    }
    export function useApollo(initialState) {
    const store = useMemo(() => initializeApollo(initialState), [initialState])
    return store
    }

    utils/auth0.ts

    ts

    import { initAuth0 } from '@auth0/nextjs-auth0'
    import getConfig from 'next/config'
    const { serverRuntimeConfig } = getConfig()
    const { auth, cookieSecret } = serverRuntimeConfig
    export default initAuth0({
    ...auth,
    session: {
    cookieSecret,
    cookieLifetime: 60 * 60 * 8,
    storeIdToken: false,
    storeAccessToken: false,
    storeRefreshToken: false,
    },
    oidcClient: {
    httpTimeout: 2500,
    clockTolerance: 10000,
    },
    })

    next.config.js

    js

    require('dotenv').config()
    const {
    AUTH0_CLIENTID,
    AUTH0_DOMAIN,
    AUTH0_CLIENT_SECRET,
    AUTH0_SCOPE,
    AUTH0_COOKIE_SECRET,
    BACKEND_ADDRESS,
    } = process.env
    module.exports = {
    publicRuntimeConfig: {
    BACKEND_URL: `${BACKEND_ADDRESS}/api/graphql`,
    },
    serverRuntimeConfig: {
    auth: {
    domain: AUTH0_DOMAIN,
    clientId: AUTH0_CLIENTID,
    clientSecret: AUTH0_CLIENT_SECRET,
    scope: AUTH0_SCOPE,
    redirectUri: `${BACKEND_ADDRESS}/api/callback`,
    postLogoutRedirectUri: `${BACKEND_ADDRESS}/`,
    },
    cookieSecret: AUTH0_COOKIE_SECRET,
    },
    }

    Make sure to restart the server by pressing ctrl+c on the terminal window and starting it back up again with npm run dev.

    pages/api/login.ts

    ts

    import auth0 from '../../utils/api/auth0'
    export default async function login(req, res) {
    try {
    await auth0.handleLogin(req, res, {})
    } catch (error) {
    console.error(error)
    res.status(error.status || 500).end(error.message)
    }
    }

    pages/api/logout.ts

    ts

    import auth0 from '../../utils/api/auth0'
    export default async function logout(req, res) {
    try {
    await auth0.handleLogout(req, res)
    } catch (error) {
    console.error(error)
    res.status(error.status || 500).end(error.message)
    }
    }

    pages/api/me.ts

    ts

    import auth0 from '../../utils/api/auth0'
    export default async function me(req, res) {
    try {
    await auth0.handleProfile(req, res)
    } catch (error) {
    console.error(error)
    res.status(error.status || 500).end(error.message)
    }
    }

    pages/callback.ts

    ts

    import auth0 from '../../utils/api/auth0'
    export default async function callback(req, res) {
    try {
    await auth0.handleCallback(req, res, { redirectTo: '/' })
    } catch (error) {
    console.error(error)
    res.status(error.status || 500).end(error.message)
    }
    }