Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Discussion options

Summary

I have a NestJS backend that has its own authentication in jwt and NextJs + next-auth application and I want to implement login by Google functionality but next auth is using its own generated token I want next-auth to use my own access tokens from the NestJS backend, how can I do that?

I tried to put the callback URL to the backend to send the authenticated user to the backend and redirect the request to the next auth callback with the user from the database with the custom-generated token

next-auth Provider

GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      authorization: {
        params: {
          request_uri: `${process.env.BACKEND_URL}/auth/google/callback`,
        },
      },
    }),

in Nest

@Public()
    @Get('google/callback')
    @UseGuards(GoogleOAuthGuard)
    @Redirect('f')
    googleAuthRedirect(@Request() req) {
        console.log('success');
        return null;
        // return this.appService.googleLogin(req);
    }

but after the user login with his Google account, I got an error from the backend

missing code verifier
How can I tell next-auth to store the user from the nest backend database that is authenticated by Google, not the user is returned by Google?

Additional information

No response

Example

No response

You must be logged in to vote

I have made an API route in the backend that takes Google token and verifies it and if the token is valid it returns the logged-in user from the database and in the sign-in callback in the next auth I set the user from the backend

    async signIn({ user, account }) {
      if (account?.provider === "google") {
        const dbUser = await fetch(
          `${process.env.BACKEND_URL}/auth/google/token?token=${account?.id_token}`,
          {
            method: "GET",
            headers: {
              "Content-Type": "application/json",
            },
          },
        ).then((r) => r.json());

        if (!dbUser?.data?.user) return false;

        user.id = dbUser?.data?.user?.id;

Replies: 4 comments · 10 replies

Comment options

Hi! Any update?

You must be logged in to vote
1 reply
@msobkyy
Comment options

check the answer

Comment options

Any updates?

You must be logged in to vote
3 replies
@msobkyy
Comment options

check the answer

@emimaricic
Comment options

would you be able to provide a source code please, if I could see what am I doing wrong...

@emimaricic
Comment options

I have a problem when JWT expires on backend I don't know how to refresh it and get a new one

Comment options

I have made an API route in the backend that takes Google token and verifies it and if the token is valid it returns the logged-in user from the database and in the sign-in callback in the next auth I set the user from the backend

    async signIn({ user, account }) {
      if (account?.provider === "google") {
        const dbUser = await fetch(
          `${process.env.BACKEND_URL}/auth/google/token?token=${account?.id_token}`,
          {
            method: "GET",
            headers: {
              "Content-Type": "application/json",
            },
          },
        ).then((r) => r.json());

        if (!dbUser?.data?.user) return false;

        user.id = dbUser?.data?.user?.id;
        user.email = dbUser?.data?.user?.email;
        user.firstName = dbUser?.data?.user?.firstName;
        user.lastName = dbUser?.data?.user?.lastName;
        user.avatar = dbUser?.data?.user?.avatar;
        user.isEmailVerified = dbUser?.data?.user?.isEmailVerified;
        user.isPhoneVerified = dbUser?.data?.user?.isPhoneVerified;
        user.token = dbUser?.data?.accessToken;

        return true;
      }
      return true;
    },
You must be logged in to vote
5 replies
@poby123
Comment options

I appreciate it! 😄

@trongtai37
Comment options

Hi @msobkyy, how did you verify the Google token?
Is this API route ${process.env.BACKEND_URL}/auth/google/token?token=${account?.id_token} protected?

@VelHRH
Comment options

The verification can be like this:

async function verifyIdToken(idToken) {
  try {
    const ticket = await client.verifyIdToken({
      idToken,
      audience: GOOGLE_CLIENT_ID, 
    });
    const payload = ticket.getPayload();
    
    const currentTimestamp = Math.floor(new Date().getTime() / 1000);
    if (payload.exp < currentTimestamp) {
      throw new Error();
    }

    if (payload.aud !== CLIENT_ID) {
      throw new Error();
    }

    return payload;
  } catch (error) {
    throw new Error();
  }
}
@ofoetey
Comment options

A year past and this is still relevant, thanks @msobkyy

@schbudy
Comment options

Thanks @msobkyy for save my day

Answer selected by msobkyy
Comment options

i guess this is the solution but this is a little bit bad for someone who wants flexibility,
like next auth depends upon the database adapter , what if someone's database is not in next js .

like i have prisma in my nest js project with a great schema , account , user, tokens ,blacklisting etc
i don't want to be redundant having two prisma files and , and like generating types on both sides etc .
and i did not find a solution like using it without a database adapter , my oauth is in nest js with custom strategies and guards.

next auth is nice when you want to have a solution only in nextjs , like it is limited , but if backend is somewhere else , like an api , it is a disaster i guess.

You must be logged in to vote
1 reply
@caturbgs
Comment options

100% true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
🙏
Help
Labels
None yet
10 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.