Next.js Discord

Discord Forum

invalid_grant Next Auth/Next 13 Google Provider

Unanswered
evro posted this in #help-forum
Open in Discord
I'm wondering if anyone has solved this issue which may be a bug w/ nextauth itself. I'm unable to refresh the token when using nextAuth Google Providers.

Error refreshing access token: RefreshAccessTokenError {
  error: 'invalid_grant',
  error_description: 'Token has been expired or revoked.'
}


Code:
let authOptions: NextAuthOptions;
let handler;

try {
  authOptions = {
    session: {
      strategy: 'database',
      maxAge: 4 * 60 * 60, // 4 hours
      updateAge: 60 * 60, // 1 hour
    },
    adapter: PrismaAdapter(prisma),
    secret: process.env.NEXTAUTH_SECRET,
    providers: [
      Google({
        clientId: process.env.GOOGLE_CLIENT_ID || '',
        clientSecret: process.env.GOOGLE_CLIENT_SECRET || '',
        authorization: {
          params: {
            prompt: 'consent',
            access_type: 'offline',
            response_type: 'code',
            wellKnown:
              'https://accounts.google.com/.well-known/openid-configuration',
            idToken: true,
            scope: scopes.join(' '),
          },
        },
        profile(profile) {
          return {
            id: profile.sub,
            name: profile.name,
            email: profile.email,
            image: profile.picture,
            role: profile.role,
          };
        },
      }),
    ],
    pages: {
      signIn: '/auth/signin',
    },
    callbacks: {
      session: async ({ session, user }) => {
        const [google] = await prisma.account.findMany({
          where: { userId: user.id, provider: 'google' },
        });
        if (google.expires_at * 1000 < Date.now()) {
          try {
            const response = await fetch(
              'https://oauth2.googleapis.com/token',
              {
                headers: {
                  'Content-Type': 'application/x-www-form-urlencoded',
                },
                body: new URLSearchParams({
                  client_id: process.env.GOOGLE_CLIENT_ID ?? '',
                  client_secret: process.env.GOOGLE_CLIENT_SECRET ?? '',
                  grant_type: 'refresh_token',
                  refresh_token: google.refresh_token,
                }),
                method: 'POST',
              }
            );

            const tokens = await response.json();

            console.log('tokens', tokens);
            

            if (!response.ok) throw tokens;

            await prisma.account.update({
              data: {
                access_token: tokens.access_token,
                expires_at: Math.floor(Date.now() / 1000 + tokens.expires_in),
                refresh_token: tokens.refresh_token ?? google.refresh_token,
              },
              where: {
                provider_providerAccountId: {
                  provider: 'google',
                  providerAccountId: google.providerAccountId,
                },
              },
            });
          } catch (error) {
            console.error(
              'Error refreshing access token: RefreshAccessTokenError',
              error
            );
          }
        }
        return {
          ...session,
          user: {
            ...session.user,
            id: user.id,
            role: user.role,
          },
        };
      },
      jwt: async ({ token, user }) => {
        if (user) {
          const u = user as unknown as any;
          const dbUser = await prisma.user.findUnique({
            where: { id: u.id },
            include: { role: true },
          });

          return {
            ...token,
            id: u.id,
            role: dbUser.role,
          };
        }
        return token;
      },
    },
  };
  handler = NextAuth(authOptions);
} catch (error) {
  console.error('Error setting up auth options', error);
}

export { authOptions };
export { handler as GET, handler as POST };

1 Reply

Hey, I'm facing something similar except that my problem seems to be related to Prismaadapter. No matter what i do, when i set up the providers and adapter(I'm using posgresql database), I'm constantly thrown the "le.js:254:37) {
name: 'GetUserByAccountError',
code: undefined" error. Dropping a message because, the issue is kind of related.
Been stuck with this error for 2 days now. The error pops up while using Google or any other provider. If i remove the adapter, then everything works fine.