Skip to content

Next.js - Integrate your frontend

Minimal example

The following example will display a different message for logged-in users vs logged out. We'll go into more detail about how it works and show more advanced examples down below.

// pages/_app.jsx
import {AuthProvider} from "@propelauth/react";

const MyApp = ({Component, pageProps}) => {
    return <AuthProvider authUrl={process.env.NEXT_PUBLIC_PROPELAUTH_AUTH_URL}> //(1)
        <Component {...pageProps} />
    </AuthProvider>
}

export default MyApp
  1. Your auth URL can be found in your PropelAuth dashboard. You will have a different URL for your test and production environment, so you may want to store it in an ENV variable.
// pages/index.js
import {withAuthInfo} from "@propelauth/react";

const IndexPage = withAuthInfo((props) => {
    // isLoggedIn and user are injected automatically from withAuthInfo
    if (props.isLoggedIn) {
        return <div>You are logged in as {props.user.email}</div>
    } else {
        return <div>You are not logged in</div>
    }
})

export default IndexPage

Technical details

When a user logs in via your hosted pages, a secure, http-only cookie is created. This cookie allows PropelAuth to identify logged-in users. In production, we require you use a custom domain to avoid third-party cookie issues for your users. Browsers like Safari will block cookies across domains, which is why we include custom domains even in our free plan.

Afterwards, your frontend can make a request to PropelAuth to determine if the current user is logged in and get their information.

auth overview

On top of user information, your frontend will get an access token for that user. These tokens are JWTs, which we've written about here.

Later on, when your frontend makes requests to your backend, it will include an access token, which your backend can validate and determine whose token it is. This validation is done entirely on your backend and doesn't need to make any requests to PropelAuth.

The access token is short-lived, and our libraries will refresh the token both periodically and when the user switches to your tab or reconnects to the internet.

Configure

Go to your PropelAuth project and click Frontend Integration in the sidebar. You will see:

  • Port - The port your app runs on locally. The default for Next.js is 3000. After entering 3000, your test environment will only accept requests from http://localhost:3000.

  • Login Redirect Path - After a user logs in, they will be redirected here. For example, / will redirect them to http://localhost:3000/.

  • Logout Redirect Path - After a user logs out, they will be redirected here.
  • Auth URL - This is where your authentication pages are hosted, and you will need this for the setup step.

Install

In your Next.js app, install the @propelauth/react library.

$ npm install --save @propelauth/react
$ yarn add @propelauth/react

Set up - AuthProvider

AuthProvider is the provider of a React context that manages the current user's access token and metadata. You cannot use any of the other hooks without it.

In other words, the AuthProvider is the component that actually manages authentication information, and every other component/function fetches from it.

It's best to put it at the top level of your application, so it never unmounts.

import {AuthProvider} from "@propelauth/react";

ReactDOM.render(
    <AuthProvider authUrl={process.env.REACT_APP_AUTH_URL}> // (1)
        <YourApp/>
    </AuthProvider>,
    document.getElementById("root")
);
  1. The authUrl is the base URL where your authentication pages are hosted. You can find this under the Frontend Integration section for your project.

Get current user information

There are three options for getting the current user's information:

import {withAuthInfo} from '@propelauth/react';

function MinimalExample(props) {
    // isLoggedIn and user are injected automatically from withAuthInfo below
    if (props.isLoggedIn) {
        return <div>You are logged in as {props.user.email}</div>
    } else {
        return <div>You are not logged in</div>
    }
}

export default withAuthInfo(MinimalExample); // (1)
  1. A React Higher-Order Component that provides common values like isLoggedIn and accessToken. These values are injected into the props of your component.
import {withRequiredAuthInfo} from '@propelauth/react';

function MinimalExample(props) {
    // user is injected automatically from withRequiredAuthInfo below
    return <div>You are logged in as {props.user.email}</div>
}

export default withRequiredAuthInfo(MinimalExample); // (1)
  1. Similar to withAuthInfo, except if the user isn't logged in, they are redirected to the login page (that behavior is configurable).
import {useAuthInfo} from '@propelauth/react';

function MinimalExample() {
    const authInfo = useAuthInfo()

    // Unlike the higher order functions, we need to check the loading case now
    if (authInfo.loading) {
        return <div>Loading...</div>
    } else if (authInfo.isLoggedIn) {
        return <div>You are logged in as {props.user.email}</div>
    } else {
        return <div>You are not logged in</div>
    }
}

export default MinimalExample;

When is an external API call made?

The AuthProvider manages all external API requests. withAuthInfo, withRequiredAuthInfo, and useAuthInfo are only getting information out of it and make no requests themselves. In other words, you can (and should) add as many uses of these functions as you need - they will not cause you to make additional requests.

withAuthInfo

withAuthInfo(Component, {
    displayWhileLoading: <div>Loading...</div>, // (1)
})
  1. A React element to display while the AuthProvider is fetching auth information. Defaults to an empty element

which will inject the following props into Component:

Prop Description
accessToken If the user is logged in, this is a string you can use to access your APIs on behalf of this user. Otherwise, null
isLoggedIn Whether or not the user is logged in
orgHelper An object with useful functions for managing organizations
user If the user is logged in, this contains metadata about them. Otherwise, null

withRequiredAuthInfo

withRequiredAuthInfo(Component, {
    displayWhileLoading: <div>Loading...</div>, // (1)
    displayIfLoggedOut: <div>You are logged out</div> // (2)
})
  1. A React element to display while the AuthProvider is fetching auth information. Defaults to an empty element
  2. A React element to display if the current user is logged out. Defaults to <RedirectToLogin />

This is identical to withAuthInfo, except Component is only rendered if the user is logged in. You are guaranteed that isLoggedIn is true and the accessToken is not null.

useAuthInfo

function Component() {
    const authInfo = useAuthInfo()
    // ...rest of the component
}

A React hook which gets auth information. authInfo contains:

Key Description
loading True if the AuthProvider is still fetching auth information. This will only happen once when the application is first loaded.
accessToken If the user is logged in, this is a string you can use to access your APIs on behalf of this user. Otherwise, null
isLoggedIn Whether or not the user is logged in
orgHelper An object with useful functions for managing organizations
user If the user is logged in, this contains metadata about them. Otherwise, null

Other utilities

  • useLogoutFunction - Returns a function we can call to log our current user out
  • useRedirectFunctions - Returns a set of functions we can call to redirect the user to different pages (e.g. signup, login).

For a complete list, see the reference. Alternatively, our guides will walk you through the process of creating an entire application end to end.

Organizations

The orgHelper which is provided by withAuthInfo, withRequiredAuthInfo, or useAuthInfo exists to make the current user's organization information easy to manage. It's an object which has the following functions (types included) on it:

type OrgHelper = {
    // returns all orgs that the user is a member of
    getOrgs: () => OrgMemberInfo[],
    // returns all org ids that the user is a member of
    getOrgIds: () => string[],
    // returns org information for a given orgId
    getOrg: (orgId: string) => OrgMemberInfo | undefined,
    // returns org information for a given org by name
    getOrgByName: (orgName: string) => OrgMemberInfo | undefined,

    // Applications have users that can be in multiple organizations.
    // However, very commonly, your user will only interact with one at a time.
    // These functions allow you to select an org, which your application can fetch.
    // See the examples below for more details
    selectOrg: (orgId: string) => void,

    // inferDefault, if true, will deterministically select an organization 
    //   if one hasn't yet been explicitly selected.
    // The order is:
    //   - Organizations selected with selectOrg
    //   - Previously selected organizations (uses localStorage to survive new tabs/refreshes)
    //   - Alphabetical order by name
    // Default is true
    getSelectedOrg: (inferDefault?: boolean) => OrgMemberInfo | undefined,
    getNotSelectedOrgs: (inferDefault?: boolean) => OrgMemberInfo[],
}
type OrgMemberInfo = {
    orgId: string;
    orgName: string;
    userRole: UserRole;
};

enum UserRole {
  Member = 0,
  Admin = 1,
  Owner = 2,
};

Making an authenticated HTTP request

There are a lot of ways to make HTTP requests in Javascript. You could use the Fetch API, XMLHttpRequest, or a library like axios.

Whichever you choose, to make an authenticated request on behalf of your user, you'll need to provide an access token. Just like isLoggedIn and user, the access token is available from withAuthInfo. You provide it in the request in the Authorization header, like so:

Authorization: Bearer YOUR_ACCESS_TOKEN

With the Fetch API, this looks like:

function whoAmI(accessToken) {
    return fetch("/whoami", {
        method: "GET",
        headers: {
            "Authorization": `Bearer ${accessToken}`,
        }
    })
}

Examples

See the reference for detailed examples.

Next Steps

Done with your frontend? Next you can integrate your backend.