Search code examples
next-auth

NextAuth - How to incrementally expand authenticated scope?


Hello I'm using the google auth provider with firebase/firestore (incidentally, i had to hack the firebase adapter following this )

I want to be able to incrementally expand scope with the GAPI, as this is the best practice for user experience:

Login with google provider and the base scope When the user requests higher-permission services, pop the oauth screen again to expand scope Is there a good way to do this?

thanks


Solution

  • I resolved this by adding two providers and then calling the different providers in sequence

    Next-Auth config: /api/auth/[...nextauth.ts]

    import GoogleProvider from "next-auth/providers/google"; // from next auth
    import GmailProvider from "next-auth-custom/GmailProvider"; // from below
    
    export default NextAuth({
      providers: [
        GoogleProvider(config),
        GmailProvider(config),
      ]
    });
    

    GmailProvider at next-auth-custom/GmailProvider

    import type { OAuthConfig, OAuthUserConfig } from "next-auth/providers";
    import { GoogleProfile } from "next-auth/providers/google";
    export interface Google extends Record<string, any> {
      aud: string;
      azp: string;
      email: string;
      email_verified: boolean;
      exp: number;
      family_name: string;
      given_name: string;
      hd: string;
      iat: number;
      iss: string;
      jti: string;
      name: string;
      nbf: number;
      picture: string;
      sub: string;
    }
    
    export default function Google<P extends GoogleProfile>(
      options: OAuthUserConfig<P>
    ): OAuthConfig<P> {
      return {
        id: "gmail",
        name: "Gmail",
        type: "oauth",
        wellKnown: "https://accounts.google.com/.well-known/openid-configuration",
        authorization: {
          params: {
            scope: "openid https://www.googleapis.com/auth/gmail.send",
          },
        },
        idToken: true,
        checks: ["pkce", "state"],
        profile(profile) {
          return {
            id: profile.sub,
            name: profile.name,
            email: profile.email,
            image: profile.picture,
          };
        },
        options,
      };
    }
    
    

    Button which takes the provider as a prop:

    const GoogleLoginButton: React.FC<ButtonProps> = ({
      prompt = "Login with Google",
      provider = "google",
    }) => {
      return (
        <GoogleButton onClick={() => signIn(provider)}>
          <FaGoogle /> {prompt}
        </GoogleButton>
      );
    };
    
    export default GoogleLoginButton;