Using Next Js for Google authentication with Strapi CMS

Recently, I've been working on implementing Google authentication in my Next.js and Strapi application.

However, every time I attempt to do so, I encounter the following error:

Error: This action with HTTP GET is not supported by NextAuth.js
.

The issue seems to be rooted in the code found in 'api/auth/[...nextauth].jsx'

import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";

const options = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
  ],
  secret: process?.env?.NEXT_PUBLIC_SECRET,
  callbacks: {
    async session({ session, token }) {
      session.jwt = token.jwt;
      session.id = token.id;
      return session;
    },
    async jwt({ token, user, account }) {
      if (user) {
        const response = await fetch(
          `${process.env.NEXT_PUBLIC_API_URL}/auth/${account.provider}/callback?access_token=${account.access_token}`
        );
        const data = await response.json();
        token.jwt = data.jwt;
        token.id = data.user.id;
      }
      return token;
    },
  },
};

const Auth = (req, res) => NextAuth(req, res, options);

export default Auth;

I have ensured that the redirect URIs specified in the Google console are:

https://frontend.com/api/auth/callback/google
https://backend.com/api/auth/callback/google

Additionally, the redirect URI in Strapi has been set as:

https://frontend.com/api/auth/callback/google

Answer №1

I successfully configured Strapi with the Google provider as an authenticator and integrated it into my NextJS project using NextAuth in the following manner.

  • Strapi v3.6.8 is running on localhost:1337

  • The Frontend NextProject -v 12.2.3 runs on localhost:3000

  • "next-auth": "^4.10.3" has been installed in the NextJS project

In my Strapi Google provider configuration:

The redirect URL to your front-end app:

  • http://localhost:3000/api/auth/google

In the Google console: Under Credentials -> OAuth 2.0 Client IDs:

Authorized redirect URIs:

  • http://localhost:1337/connect/google/callback
  • http://localhost:3000/api/auth/callback/google

[...nextauth].ts - /pages/api/auth/[...nextauth].ts

import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"

export default NextAuth({

    providers: [
        GoogleProvider({
            clientId: process.env.GOOGLE_CLIENT_ID,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET,
        }),
    ],

    session: { strategy: "jwt" },

    callbacks: {

        async session({ session, token, user }) {
            session.jwt = token.jwt;
            session.id = token.id;
            return session;
        },

        async jwt({ token, user, account }) {

            const isSignIn = user ? true : false;
            if (isSignIn) {
                const response = await fetch(
                    `${process.env.NEXT_PUBLIC_API_URL}/auth/${account?.provider}/callback?access_token=${account?.access_token}`
                );
                const data = await response.json();
                token.jwt = data.jwt;
                token.id = data.user.id;
            }
            return token
        }
    }

});

On your page utilize the following function from Next for signing in.

import { signIn } from "next-auth/react";
signIn();

Update:

For Strapi 4.3.0 I had to modify the URL in JWT callback from

http://localhost:1337/auth/google/callback?access_token={accessToken}

to

http://localhost:1337/api/auth/google/callback?access_token={accessToken}

Answer №2

Initially, I encountered an issue with the authentication flow that didn't sit well with me. I couldn't figure out a way to resolve it.

The requirement for the next authentication step seemed unnecessary to me. Why was it necessary? Whether it was adequately explained or not, I wasn't convinced.

However, I stumbled upon a solution miraculously.

To address the issue, I created a new file [provider].js within the /pages/auth directory.

Note: It's important to highlight that the file is not located inside the /pages/api/auth folder

    import React from "react";
    
    import { api } from "../../services/api";
    
    export async function getServerSideProps({
      params: { provider },
      query: { access_token },
      ...ctx
    }) {
      const res = await api(
        `/auth/${provider}/callback?access_token=${access_token}`,
        "GET"
      );
      if (res?.jwt) {
         //perform desired action
      }
    
      return {
        props: { },
      };
    }
    
    const Connect = () => {
   
      return (
        <div>
          Redirecting...
        </div>
      );
    };
    
    export default Connect;

The redirect URL to my front-end application:

http://localhost:3000/auth/google

In Google console: Located under Credentials -> OAuth 2.0 Client IDs:

Authorized redirect URIs:

http://localhost:1337/connect/google/callback
http://localhost:3000/auth/callback/google

Fortunately, this solution worked seamlessly even in a production environment.

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

Having trouble obtaining the serialized Array from a Kendo UI Form

I am working on a basic form that consists of one input field and a button. Whenever the button is clicked, I attempt to retrieve the form data using the following code: var fData = $("#test").serializeArray(); Unfortunately, I am facing an issue where I ...

The path NPM Package is missing in the package export

For my first NPM package, I've been diving into the manuals and exploring other projects for hours to make everything work. Getting Started with the Project The package successfully builds, generating files for ESM and CommonJS targets. It installs s ...

What is the best way to prevent the page from constantly refreshing?

Recently, I developed a code snippet that detects the user's geolocation and changes the currency accordingly. The functionality works as intended, but there is an issue where the page keeps refreshing due to the presence of certain code. If I remove ...

Troubleshooting the "Request failed with status code 500" error when refreshing a page in a React application

Every time the page is reloaded, an error message pops up saying: Uncaught (in promise) Error: Request failed with status code 500. Here's the code in list.tsx: const [state, setState] = useState([]); const { getRoom } = useRoom(); const fe ...

Encountering an error message: [$parse:syntax] when trying to implement ng-class

I'm currently working on developing custom form validation, utilizing ng-class to emphasize required fields. Here is the syntax I am using: <div class="form-group" ng-class="{'has-error': dc.{fname}.nedatt({{fname}}.username)}"> ...

How to manage simultaneous requests in Parse Server Cloud Code

Imagine having some Cloud Code running on a Parse Server: Parse.Cloud.beforeSave("UserProfiles", function(request, response) { const query = new Parse.Query("UserProfiles"); query.equalTo("user", request.user); query.count({ success: f ...

Tips for aligning text in an InputBase component from material-ui

I'm attempting to center the text area of an InputBase component from material-ui. I'm currently unsure if this is a bug or not. You can view an example of how I tried to center the text area here. Here is my code: import { InputBase, makeS ...

Is there a way to update a single element within an array without triggering a refresh of the entire array?

Is there a way to prevent the component from rerendering every time new data is input? I attempted to memoize each cell but I am still facing the same issue. Any suggestions on how to accomplish this? import React, { useState, memo } from "react&quo ...

Searching is disrupted when the page is refreshed in NextJS

When I refresh the page, router.query.title disappears. I have read that I need to use getServerSideProps, but I'm unsure of what to include in the function. Can anyone provide guidance on how to resolve this issue? Update: I followed Yilmaz's s ...

Ways to prevent recurring variables in Twitter bootstrap dialogues

I need assistance with deleting multiple links using ajax: <a id="id-1">link1</a> <a id="id-2">link2</a> <a id="id-3">link2</a> <a id="id-4">link2</a> ... This is the simplified version of my code: $(docum ...

Sending a form cancellation submission within a nested function call

I need help preventing my form from submitting in case the confirmation message is cancelled. How can I achieve this within the each() loop? $('#myForm').submit(function() { var inputs = $(this).find('input:checked'); inputs.ea ...

Is it possible to synchronize Vue data values with global store state values?

I need help updating my data values with values from store.js. Whenever I try the code below, I keep getting a blank page error. Here's how I have it set up in App.vue: data() { return { storeState: store.state, Counter: this.storeState.C ...

Converting the jQuery $.xajax loadmore feature into a custom XMLHttpRequest JavaScript function

I'm facing challenges while trying to create a XMLHttpRequest loadmore function as compared to using $.ajax. I am uncertain about what I might be missing in my code. Below is the function that is based on a previously working $.ajax version that I ha ...

The error message "angularjs is unable to assign a value to the property 'students' as it is

After setting ClassesServices to the classes array, I tried adding students of the class to a new property called classes.students. However, I encountered an error message saying 'Cannot set property 'students' of undefined.' $scope.cl ...

Please provide TypeScript code for a React wrapper function that augments a component's props with two additional functions

During the course of my project, I implemented a function wrapping React component to incorporate undo/redo functionality using keyboard shortcuts Ctrl+Z and Shift+Ctrl+Z. Here is an example: import React from 'react'; interface WithUndoRedoProp ...

Javascript timer that counts down using cookies for storage

Seeking assistance - I am in search of a solution to create a javascript countdown timer that utilizes cookies. I need the timer to remain consistent even when the user refreshes the page, until a specific time has elapsed. This is for an online examinat ...

Incorporating an image within a v-for loop in Vuetify

I am planning to incorporate images at a later stage, but I am currently utilizing v-for and facing a dilemma of how to seamlessly introduce the image within the loop without disrupting its flow. <template> <v-card> <p v-for="item ...

IE11 experiences frequent crashes when running a web application utilizing the Kendo framework and JavaScript

I am experiencing difficulties with my ASP.NET MVC application that utilizes Kendo UI and jQuery. Specifically, when using Internet Explorer 11, the browser crashes after a short period of usage. The crash does not seem to be linked to any specific areas o ...

Can you explain to me the syntax used in Javascript?

I'm a bit puzzled by the syntax used in this react HOC - specifically the use of two fat arrows like Component => props =>. Can someone explain why this works? const withLogging = Component => props => { useEffect(() => { fetch(`/ ...

Issue with scrolling feature in div

I am currently facing an issue with scrolling on my website. Visit this site to see the problem. When scrolling down, it causes the "hidden" part of the site to slide up. I want to achieve a similar sliding effect, but it needs to be smooth. I have attempt ...