Implementing next-auth with graphql apollo for seamless data retrieval

Hello everyone on stackoverflow,

I could really use some assistance, please.

Currently, I am dealing with a GraphQL data source and utilizing apollo client to fetch that data. Specifically, I am focusing on my login function where I am incorporating the next-auth credential provider: [Modified code below showing the fetch call to graphql]

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

export default NextAuth({
    session: {
        strategy: 'jwt',
    },
    callbacks: {
        async jwt({ token, user}: any) {
            if(user?._id) token._id = user._id;
            return token;
        },
        async session({ session, token}: any) {
            if(token?._id) session.user._id = token._id;
            return session;
        },
    },
    providers: [
        CredentialsProvider({
            async authorize(credentials: any) {
                const query = `query User($email: String!) { user(email: $email) { id, username, email, password, }}`;
                const response: any = await fetch('http://localhost:4000/graphql', {
                    method: "POST",
                    headers: {"Content-Type": "application/json","Accept": "application/json", },
                    body: JSON.stringify({query, variables: { email: credentials.email }})
                });
                const {data}: any = await response.json();
                if(data) {
                    return {
                        _id: data.user.id,
                        name: data.user.username,
                        email: data.user.email,
                    };
                } 
                throw new Error("Invalid email or password");
            },
        }),
    ],
}); 

Here is my getUser hook [Omitted this section as it is not relevant anymore]

// import { useQuery, gql } from '@apollo/client';

// const Get_User = gql`
// query User($email: String!) {
//   user(email: $email) {
//     id
//     username
//     email
//     password
//   }
// }
// `;


// export default function getUser(email: any) {
//     const { error,  data } = useQuery(Get_User, {variables: {email}});

//     return {
//         error,
//         data,
//     }
// }

I have confirmed that my next-auth endpoint is operational by disabling the GraphQL getUser and adjusting the if statement comparison to itself (credential.password === credential.password), returning static data instead.

The values within the credentials object are accessible correctly.

[YES I WAS :( ] I believe I may be breaching some rules regarding react hooks here, but I am struggling to pinpoint the issue. Any insights would be greatly appreciated. Thank you in advance! ^-^

It appears there might be an issue with the timing of my fetch calls as the user details are not being returned as expected, even though the fetch request works when tested on another page.

Answer №1

If you are utilizing a hook within a function that is not a React component, such as when your GetUser function returns an object rather than components, it may cause issues. Additionally, keep in mind that useQuery operates asynchronously, meaning the function will not immediately return data.

To address this, consider utilizing client.query within a function where client represents your Apollo client object. Alternatively, you can use useQuery within an actual React component to ensure proper execution.

Answer №2

In summary, I made a mistake by misunderstanding how the technology I was using should function. I incorrectly assumed that I could simply execute useQuery from the Apollo library as a next-auth provider, which led to me violating React's hook policy. What I should have done is directly fetch data from GraphQL either using another library like axios or the fetch api. Here is my final code:

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

export default NextAuth({
session: {
    strategy: 'jwt',
},
callbacks: {
    async jwt({ token, user}) {
        if(user?._id) token._id = user._id;
        return token;
    },
    async session({ session, token}) {
        if(token?._id) session.user._id = token._id;
        return session;
    },
},
providers: [
    CredentialsProvider({
        async authorize(credentials) {
            const query = `query Users {
                users {
                  id
                  username
                  email
                  password
                }
              }`;

            const response = await fetch('http://localhost:4000/graphql', {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({query})
            });
            const { data } = await response.json();
            const user = await data.users.find((dat) => dat.email === credentials.email);
            if(user && user.password === credentials.password) {
                return {
                    _id: user._id,
                    name: user.username,
                    email: user.email,
                };
            } 
            throw new Error("Invalid email or password");
        },
    }),
],
});

I wanted to clarify my understanding based on @michel's guidance. This is my revised answer. Thank you!

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

Nested Tagged Union Types in Typescript

Imagine having the following types (syntax similar to Elm/Haskell): type Reply = LoginReply | LogoutReply type LoginReply = LoginSucceeded | AlreadyLoggedIn String When trying to represent this in Typescript using discriminated unions, a challenge arises ...

Incorporate keyboard input functionality into an object wrapper

Adding typing to a class that encapsulates objects and arrays has been a bit tricky. Typing was easily implemented for objects, but ran into issues with arrays. interface IObject1 { value1: string, } interface IObject2 { myObject: IObject1, ...

During the build process, the parameters in Next.js are not accessible

I am currently using Next.js 13 with the experimental app directory. My application utilizes dynamic routing in the following format: https://app.domain/[itemid]/[slug] Within my [slug] directory, if I create a server-side route file pages.jsx with th ...

The observed function remains untouched

In my code, I have an if condition inside a function that looks like this: public setOption() { setTimeout(() => { if (this.isCMode && !this.quest['isCompleted']) { this.toggleOption(false); } },window['TIME ...

What are the steps to conducting authenticated Supabase queries through a NextJS api route?

I'm encountering difficulties with the documentation and struggling to understand how I should authenticate my requests to the database. My Row Level Security settings only allow users to modify items that they own, identified by a column containing t ...

When a parameter is passed into a React-Query function with an undefined value, it can lead to the API returning a 404 error

Two parameters are sent from the frontend to trigger a GET request in another TypeScript file. It seems that one of the parameters is not successfully passed due to unknown rerenders, resulting in a 404 Error being returned by the API call in the console. ...

Incorporating the Observable Type into a TypeScript Interface

I want to create a TypeScript interface that looks like this: declare namespace UserService { interface IUserService { // Error: "Observable" can't be found getUsers(): Observable<Array<UserService.IUser>>; } ...

The 'get' property in the class 'ToastInjector' cannot be assigned to the 'get' property in its base class 'Injector'

error TS2416: The property 'get' in the type 'ToastInjector' cannot be assigned to the same property in the base type 'Injector'. The type '(token: any, notFoundValue?: T, flags?: InjectFlags) => ToastPackage | T&apos ...

Utilizing DataLoader in tandem with Mongoose: A comprehensive guide

I am currently working on implementing DataLoader with Mongoose for the following use case: export const PurchaseOrderType = new GraphQLObjectType({ name: "PurchaseOrder", description: "PurchaseOrder", interfaces: () => [NodeInterface], ...

Error in next.js when navigating to a different route with incorrect image being

I am experiencing an issue with my [trainers].tsx page where the data loads correctly, but the image does not load properly. Instead, I can see a previous image from another page (../2) before the correct image is displayed. For instance, when I navigate ...

Tips for omitting the trailing slash from a specific route in Next.js

Having an issue with Next.js Trailing Slash on certain pages. I have implemented a media query like: /example?type=something However, when adding a trailing slash, it becomes: /example/?type=something Is there a way to eliminate the trailing slash on p ...

Creating a Record instance consisting of a specific key and its corresponding value

Sorry for the complexity, I've struggled to simplify this further. Feel free to update the question title for more specificity. I aim to define a foundational data type structure: type AbstractBaseTypes = { [key: string]: { inputTypes ...

mongodb is experiencing issues with the findOneAndUpdate operation

Below is the code snippet for updating the database. let profileUrl = 'example' UserSchemaModel.findOneAndUpdate({_id:userId}, {$set: {profileUrl:profileUrl} }, {new:true}) .then((updatedUser:UserModel) => { console.log(updatedUser.profil ...

Issue: Module './App' not found in webpackSolution: Check if the module path is

I've decided to switch my .js files to .tsx in order to start using TypeScript. To incorporate TypeScript, I used the following command: yarn add typescript @types/node @types/react @types/react-dom @types/jest and began converting first index.tsx fo ...

Error in TypeScript: Module 'stytch' and its corresponding type declarations could not be located. (Error code: ts(2307))

I'm currently developing a Next.js application and encountering an issue while attempting to import the 'stytch' module in TypeScript. The problem arises when TypeScript is unable to locate the module or its type declarations, resulting in t ...

Should we utilize the component @Input as a parameter for the injected service constructor, or should we opt for the ServiceFactory

Within Angular 12 lies a simplified component structured as follows: @Component({ selector: 'app-list', templateUrl: './list.component.html', styleUrls: ['./list.component.less'] }) export class ListComponent implements ...

How to customize the button color in a Next.js application

Help Needed: Issue with Changing Default Button Color in Next.JS Web Application. The button text color appears as grey on Desktop Google Chrome, but shows up as blue on Mobile Chrome browser. I want to unify the color to be grey on both platforms. Custo ...

Developing Graph-QL for Microsoft Azure // Issue importing "okhttp3.Request"

Currently attempting to follow the tutorial at https://learn.microsoft.com/en-us/graph/tutorials/java?tabs=aad&tutorial-step=3 in order to establish connectivity to Microsoft Azure AD. Despite directly copying from the sample code, I am encountering is ...

Encountered a build issue in nextjs: identified a page lacking a default export of a React Component

I am working on a Next.js project where I need to prerender pages containing terms of service. These terms are saved as markdown files in public/tos/tos-en.md and public/tos/tos-pl.md. In the pages/tos/[locale]/index.jsx file, I have created a React compo ...

The error message "TypeError: addNewUser is not a function in React.js onSubmit

What could be causing the error message "TypeError: addNewUser is not a function"? The issue arises when I complete the form and click save, displaying the error that addNewUser is not defined as a function. The problem occurs within the following code ...