Priyanka de Silva
Priyanka de Silva

Reputation: 91

How to redirect to starting point after authorizing with auth0 in a Nextjs application using @auth0/nextjs-auth0

I'm currently using auth0 to authenticate users in a Next.js application.

I'm using the @auth0/nextjs-auth0 SDK and following along with the documentation.

However, I'm having trouble figuring out how to redirect users dynamically after login based on the page they accessed the login form from.

In the app I’m currently trying to build, users can log in from “/” which is the home page, and from the navbar element in “/browse”. However, after logging in, it always redirects back to “/”, while I would like to redirect users to “/browse” or "/browse/[id] if that is where they began the login process from.

I’ve tried using https://community.auth0.com/t/redirecting-to-another-page-other-than-using-nextjs-auth0/66920 as a guide but this method only allows me to redirect to a pre-defined route. I would like to know how I could make the redirect URL dynamic.

Thanks in advance!

Edit: I’ve managed to find a solution for now by digging in to the req object and setting the returnTo value to “referer”.

import { handleAuth, handleLogin } from '@auth0/nextjs-auth0';

const getLoginState = (req, loginOptions) => {
    return {
        returnTo: req.headers.referer
    };
  };

export default handleAuth({
    async login(req, res) {
        try {
          await handleLogin(req, res, { getLoginState });
        } catch (err) {
            res.status(err.status ?? 500).end(err.message)
        }
      }
  });

I’m not seeing any obvious problems so far but I’m not entirely sure if this method has any drawbacks, so I would appreciate any feedback.

Upvotes: 6

Views: 3714

Answers (3)

Abhishek Arora
Abhishek Arora

Reputation: 1

Here is a working code which I feel has a very clean approach.

As soon as the session ends, user will be first logged out (/api/auth/logout) so we will be capturing the lastVisited page here, post which user will be redirected to logout redirect page (read about alternative logout here).

Since, in most projects user will be coming back to the base url (localhost:3000) we can capture the lastVisited again back there and it will be automatically passed as a returnTo parameter in handleLogin. In case you have a custom login handler, make sure you don't change the returnTo param and all should work fine.

Step 1

Catch lastVisited in logout middleware

Capture the lastVisited page using the current page referrer header in the handleLogout middleware and pass as a query parameter.

// pages/api/auth/[auth0].ts
import { handleAuth, handleLogout } from 'lib/auth0'

export default handleAuth({
    async logout(req, res) {
    try {
        let callingUrl
        if (req.headers.referer) {
        callingUrl = new URL(req.headers.referer)
        }
        await handleLogout(req, res, { returnTo: `/?lastVisited=${callingUrl?.pathname}` })
    } catch (error) {
        // TODO: Need to work on the 401, 404 errors pages
        res.writeHead(401, { Location: `custom-error-page` })
        res.end()
    }
    },
})

Step 2

Fetch lastVisited from query at base URL

Now that we have the hold of page where we want to redirect back, we can capture that in getServerSideProps using req.query and that will automatically be passed as a returnTo parameter in the /login API.

// pages/index.tsx
import { ROUTES } from 'constants/routes'
import { GetServerSideProps, NextPage } from 'next'

const HomePage: NextPage = () => {
    return <><This is the base url</>
}

export const getServerSideProps: GetServerSideProps = async ({ query }) => {
    // Redirect based on the parameters or query
    const destination = query?.lastVisited?.toString() || ROUTES.DASHBOARD

    return {
    redirect: {
        destination,
        permanent: false,
    },
    }
}

export default HomePage

Hope this helps and saves some time. As I did scratch my head on this for quite a few hours.

Upvotes: 0

Redskinsjo
Redskinsjo

Reputation: 452

This library has a built-in page protection that will automatically redirect the browser toward the saved loginUrl (default is /api/auth/login but you can customize it in the <UserProvider loginUrl={*your_custom_login_path*}>.

So import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";

and export default withPageAuthRequired(*your_page_component*)

The browser will get within its redirection a query param returnTo that you can handle in your custom redirection, otherwise if you use default process of auth0 it will redirect automatically to this path after successfull login.

Upvotes: -2

Ax0n
Ax0n

Reputation: 592

How about this?

Step 1: Initialize Auth0 SDK

https://auth0.github.io/nextjs-auth0/modules/instance.html#initauth0

# /lib/auth0,js
import { initAuth0 } from "@auth0/nextjs-auth0";

export default initAuth0({
  secret: process.env.SESSION_COOKIE_SECRET,
  issuerBaseURL: process.env.NEXT_PUBLIC_AUTH0_DOMAIN,
  baseURL: process.env.NEXT_PUBLIC_BASE_URL,
  clientID: process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID,
  clientSecret: process.env.AUTH0_CLIENT_SECRET,
  routes: {
    callback:
      process.env.NEXT_PUBLIC_REDIRECT_URI ||
      "http://localhost:3000/api/auth/callback",
    postLogoutRedirect:
      process.env.NEXT_PUBLIC_POST_LOGOUT_REDIRECT_URI ||
      "http://localhost:3000",
  },
  authorizationParams: {
    response_type: "code",
    scope: process.env.NEXT_PUBLIC_AUTH0_SCOPE,
  },
  session: {
    absoluteDuration: process.env.SESSION_COOKIE_LIFETIME,
  },
});

Step 2: Configure Login

https://auth0.github.io/nextjs-auth0/modules/handlers_login.html#handlelogin

https://auth0.github.io/nextjs-auth0/interfaces/handlers_login.loginoptions.html#returnto

# /pages/api/auth/login.js

import auth0 from "../../../lib/auth0";

export default async function login(req, res) {

  let options = {
    returnTo: 'http://localhost:3000/dashboard'
  }

  try {
    await auth0.handleLogin(req, res, options);

  } catch (error) {
    console.error(error);
    res.status(error.status || 500).end(error.message);
  }
}

Now you will land on the dashboard page after successfully authenticating.

Step 3: Helpful Sanity Check

create /pages/api/auth/callback.js with the following content

import auth0 from "../../../lib/auth0";

const afterCallback = (req, res, session, state) => {
  // console.log(session)
  console.log(state)
  return session
};

export default async function callback(req, res) {
  try {
    console.log(auth0)
    await auth0.handleCallback(req, res, { afterCallback });
  } catch (error) {
    console.error(error);
    res.status(error.status || 500).end(error.message);
  }
}

Try logging in and look for the state in the console,

{ returnTo: 'http://localhost:3000/dashboard' }

Cheers!

Upvotes: 0

Related Questions