nextauthjs / next-auth

Authentication for the Web.
https://authjs.dev
ISC License
22.48k stars 2.98k forks source link

How to enable refresh token in v5 - ^5.0.0-beta.16 #10739

Closed ericqqqqq closed 2 weeks ago

ericqqqqq commented 2 weeks ago

What is the improvement or update you wish to see?

see an sample code to implement refresh token

Is there any context that might help us understand?

after setting up the google provider, i cannot get refresh token value in the old ways - account.refresh_token is undefined.

here is how i set it up

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

export const {
  handlers: { GET, POST },
  auth,
  signIn,
  signOut
} = NextAuth({
  providers: [Google],
  pages: {
    signIn: "/signin",
  },
  session: {
    strategy: "jwt",
  },
  callbacks: {
    async jwt({ token, user, account }) {
      if (account && user) {
        return {
          ...token,
          idToken: account.id_token,
        };
      }
      return token;
    },
    async session({ session, token }) {
      session.sessionToken = token.idToken as string;
      return session;
    },
  },
});

Does the docs page already exist? Please link to it.

No response

ericqqqqq commented 2 weeks ago
import NextAuth from "next-auth";
import { JWT } from "next-auth/jwt";
import Google from "next-auth/providers/google";

export const {
  handlers: { GET, POST },
  auth,
  signIn,
  signOut,
} = NextAuth({
  providers: [
    Google({
      authorization: {
        params: {
          prompt: "consent",
          access_type: "offline",
        },
      },
    }),
  ],
  pages: {
    signIn: "/signin",
  },
  session: {
    strategy: "jwt",
  },
  callbacks: {
    async jwt({ token, user, account }) {
      if (account && user) {
        return {
          ...token,
          id_token: account.id_token,
          refresh_token: account.refresh_token,
          expires_at: account.expires_at * 1000,
        };
      }

      if (Date.now() > token.expires_at) return await refresh(token);

      return token;
    },
    async session({ session, token }) {
      session.sessionToken = token.id_token as string;
      return session;
    },
  },
});

async function refresh(token: JWT) {
  try {
    const url = `https://oauth2.googleapis.com/token`;
    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
      body: new URLSearchParams({
        client_id: process.env.AUTH_GOOGLE_ID as string,
        client_secret: process.env.AUTH_GOOGLE_SECRET as string,
        refresh_token: token.refresh_token as string,
        grant_type: "refresh_token",
      }),
    });
    const refreshedTokens = await response.json();

    if (!response.ok) {
      throw refreshedTokens;
    }
    return {
      ...token,
      id_token: refreshedTokens.id_token,
      refresh_token: refreshedTokens.refresh_token ?? token.refresh_token,
      expires_at: Date.now() + refreshedTokens.expires_in * 1000,
    };
  } catch (error) {
    return {
      ...token,
      error: "RefreshAccessTokenError",
    };
  }
}

reference: i made a version that works for me.

ndom91 commented 2 weeks ago

Thanks for sharing your working example!

There's an example for the Google login parameters in the Google Provider page and a separate doc on Refresh Token Rotation, but if there's anything you see there that we could improve, we'd appreciate a PR :pray:

ericqqqqq commented 2 weeks ago

then my issue was - I couldn't easily find documentation for v5; it's usually v3 or v4. Can you put together the v5 documentation in one place?

If you already have it, could you share the link to the v5 documentation with me?

ndom91 commented 2 weeks ago

Hey @ericqqqqq yeah so the v5 one is the "refresh token rotation" link I mentioned in the previous post. It's part of our new docs site we relaunched a few weeks ago at authjs.dev.

If you find any errors or anything like that, a PR would be great :blush: