return to the original secured page based on the most recent language preference

I'm facing an issue with a logical redirection that needs to redirect users to the previous protected page after login.

The login functionality is implemented using my custom login page and Google Credentials. Additionally, I have set up a multilingual website using Next/router locale.

Below is my configuration for NextAuth:

export default NextAuth({
    adapter: MongoDBAdapter(clientPromise),
    secret: process.env.NEXTAUTH_SECRET,
    providers: [
        // OAuth authentication providers
        GoogleProvider({
            clientId: process.env.GOOGLE_ID,
            clientSecret: process.env.GOOGLE_SECRET,
        }),
    ],
    callbacks: {
        async redirect({ url, baseUrl }) {
            // Allowing relative callback URLs
            if (url.startsWith("/")) return `${baseUrl}${url}`
            // Allowing callback URLs on the same origin
            else if (new URL(url).origin === baseUrl) return url
            return baseUrl
        }
}
})

And here is the code for handling the signIn onClick event:

onClick={() => signIn("google", { callbackUrl: locale == "id-ID" ? '/app' : "/en-US/app" })}

Please let me know if you need further clarification or if there's anything you find difficult to understand. Thank you!

Answer №1

Are you searching for information on how to specify a callback URL in the Next.js authentication library? If so, you can find detailed instructionshere.

The callbackUrl parameter allows you to define the URL where the user will be redirected after signing in. By default, it redirects to the same page from where the sign-in process was initiated.

In your current implementation, you are manually redirecting users to either '/app' or '/en-US/app'.

If you want to redirect users back to the page they were trying to access before signing in, you can use the following function:

function handleSignIn() {
  const router = useRouter();
  signIn('google', { callbackUrl: router.asPath });
}
onClick={handleSignIn}

The 'redirect' callback is unnecessary since the logic you already have in place is the default behavior.

Answer №2

If authentication is necessary, consider implementing an auth context in your application. To do this, create an AuthProvider component which serves as the root component of your app. Within this component, you can validate whether the user is authenticated or not. If the user is not authenticated, you can redirect them to the login page.

import React, { createContext, useState, useEffect } from 'react';
import { useRouter } from 'next/router';

type ContextType = {
  // Define your desired ContextType values here
};

const AuthContext = createContext<ContextType>({});

export const AuthProvider: React.FC = ({ children }) => {
  const router = useRouter();
  const [authenticated, setAuthenticated] = useState<boolean>(false);
  const [user, setUser] = useState<UserType | undefined>();

  useEffect(() => {
    if (!authenticated) {
      router.replace(
        `/login?callbackUrl=${router.asPath.replace('/', '').replace(/&/g, '_')}`
      );
      return;
    }

    if (authenticated) {
      // go to default page
      if (!router.query.callbackUrl) {
        router.replace('/dashboard');
        return;
      }

      // redirects to callback url
      router.replace(`/${router.query.callbackUrl.replace(/_/g, '&')}`);
    }
  }, [authenticated]);

  useEffect(() => {
    setAuthenticated(!!user);
  }, [user]);

  const value = React.useMemo(
    () => ({
      // add all your desired ContextType values here
      // e.g., user, setUser, authenticated
    }),
    [
      // add any dependencies that should trigger a re-render here
      // e.g., user, authenticated
    ]
  );

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = (): ContextType => {
  const context = React.useContext(AuthContext);
  if (!context) throw new Error('Auth context is invalid');
  return context;
};

Now, in your _app.tsx file:

import React from 'react';
import { AuthProvider } from './auth-context';

const App: React.FC<AppProps> = ({ Component, pageProps }) => {
  return (
    <AuthProvider>
      <Component {...pageProps} />
    </AuthProvider>
  );
};

export default App;

In your login page, you can now use the auth context:

// Import setUser from useMemo
// Use setUser to handle user login

import React from 'react';
import { useAuth } from './auth-context';

const LoginPage: React.FC = () => {
  const { setUser } = useAuth();

  // Handle login logic here
  setUser(userData);
};

export default LoginPage;

Now, whenever the authenticated variable changes, your app will redirect to the desired pages. This example provides a simplified implementation of using an auth context, which can be customized to fit your specific project requirements.

I have personally used this approach in multiple projects and it has proven to work effectively.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular input range slider that automatically rounds decimal values from the data bindings

I've implemented a range slider within an Angular form to capture and display recorded values. <input [formControlName]="object.id" [id]="object.id" type="range" [(ngModel)]="object.answer" [step]="objec ...

The issue I am facing is that the map function is not functioning correctly when I click

I am currently working on a project in ReactJs that includes a sidebar with dropdown menu functionality. Desired Outcome When I click on an option in the sidebar that has a submenu, it should display that submenu and close upon another click. Curr ...

What is the procedure for extracting data from a JSON file within an HTML document?

Hey there, I am currently working on reading data from a json file using ajax. I have created a Video object that consists of Courses objects with titles and URLs. However, when attempting to read the title and URL of HTML as an example, I am not seeing a ...

Issue with Angular Checkbox: Inconsistencies in reflection of changes

I'm encountering a challenge with my Angular application where I have implemented multiple checkboxes within an options form. The issue arises when changes made to the checkboxes are not consistently displayed as expected. Below is the pertinent code ...

initiate an animated sequence upon the initialization of the Angular server

Is there a way to launch a Netflix animation after my server has started without success using setTimeout? I don't want to share the lengthy HTML and CSS code. You can view the code for the animation in question by visiting: https://codepen.io/claudi ...

Make the minimum height of one div equal to the height of another div

My query is somewhat similar to this discussion: Implementing a dynamic min-height on a div using JavaScript but with a slight twist. I am working on a dropdown menu within a WordPress site, integrated with RoyalSlider. The height of the slider div adjust ...

What steps can be taken to avoid including empty tasks in React code?

Is there a way to prevent my application from adding empty tasks? Below is the code snippet for adding a new task to an array. How can I implement a condition to block the addition of empty tasks? This application follows Mozilla's guidelines for a R ...

My goal is to monitor every action (button) that users take while using the PDF viewer

Each browser displays the view differently, and I am interested in monitoring specific user actions such as button presses on a PDF viewer. I am currently setting up an iframe and configuring its attributes. Is there a way to achieve this? ...

The ordering of my styles and Material-UI styles is causing conflicts and overrides

Greetings fellow developers! I'm currently facing an issue with my custom styles created using makeStyles(...). The problem arises when I import my styles constant from another module, and the order of the style block is causing my styles to be overr ...

waiting to display information until it is necessary

I am currently working on optimizing my website for improved loading speed and responsiveness. Users can scroll through up to 4k images, apply filters, and sort them based on their preferences. Below is the code snippet for my filtering function: function ...

What is the best way to send data back to a separate JavaScript file in ExtJS when working with records in a

I'm currently working on implementing a pop-up editing feature on a grid in extjs4. Progress so far includes successfully transferring the grid record to a popup panel located in a separate JavaScript file using the following code: handler: function( ...

Is There a Workaround for XMLHttpRequest Cannot Load When Using jQuery .load() with Relative Path?

My current project is stored locally, with a specific directory structure that I've simplified for clarity. What I'm aiming to do is include an external HTML file as the contents of a <header> element in my index.html file without manually ...

The 'catch' property is not found within the type 'PromiseLike<void>'

Help! I'm encountering a Typescript Error. An issue is arising with the 'catch' property on type 'PromiseLike<void>'. I am using Ionic and facing an error in the line containing catch: sendrequest(req: connreq) { var p ...

Positioning JQuery tooltips

I've been developing a simple tooltip tool (check out the fiddle link below), but I'm encountering some issues with positioning. My goal is to have the tooltip appear centered and above the clicked link, however right now it appears at the top le ...

I haven't encountered any type warnings in the places where I anticipated them

When I define an object like this: const x: { str: string, num: number } = { str: str, num: not_a_num }; I am surprised to find that even though 'not_a_num' is a string and not a number, the compiler does not throw an error. Instead, ...

What is the best way to create an Office Script autofill feature that automatically fills to the last row in Excel?

Having trouble setting up an Excel script to autofill a column only down to the final row of data, without extending further. Each table I use this script on has a different number of rows, so hardcoding the row range is not helpful. Is there a way to make ...

Show only child elements of a specific type within the parent div

Looking to identify divs with the class 'test' that contain only buttons in their child nodes. This is the HTML code that needs to be filtered. <div class="test"> <div> <button> <span>Button 1</span></butto ...

Is there a way to print an HTML page in Landscape mode within my Vue.js project?

I have been able to successfully print an HTML page in Landscape mode using the code below. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,maximum-scale=1.0"> ...

Using the combination of Nextjs, rsuitejs, and CSS modules ensures that no CSS files will be

In my development work, I have been utilizing Next.js in conjunction with RSuiteJS. During the development phase, everything is working smoothly without any issues. However, after building the project, I have encountered a problem where the library CSS fi ...

Managing State Changes with Redux

Reducers in Redux are primarily designed to be pure functions that take the previous state and an action as arguments, and return a new state object without mutating the previous state. However, it is still possible for developers to directly mutate the st ...