Context: I'm making an app that allows users to sign in with Google and which then makes calls to the Google Ads API on their behalf.
What works: Users can sign in and grant the app the necessary permissions, and the API calls go through successfully.
What I'm struggling with: I'd like to separate the login flow from the permissions flow. In other words, I would like users to be able to log in without granting the app any extraneous permissions, and then, later on, decide if they want to connect to their Google Ads account. This is when Google would prompt them for the necessary permissions.
Relevant code: I'm using next-auth to handle authentication, setting up the Google provider like this:
./src/pages/api/[...nextauth].ts:
[…]
GoogleProvider({
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
scope: 'https://www.googleapis.com/auth/userinfo.email openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/adwords'
}
}
}),
[…]
You can also look at my reproduction repo, a skeletal app that does nothing but make an API call to Google Ads on behalf of the logged-in user. Bootstrapped with create-t3-app using Next.js, tRPC, Tailwind and Prisma.
UPDATE: I can wrap NextAuth(options)
and take control of the endpoints
I've discovered that I can use custom initialization of the NextAuth API routes, which should provide me with an opportunity to alter the scope. Unfortunately, I'm still not sure how to provide an askForGoogleAdsPermissions
flag to next-auth/react
's signIn
function in such a way that my customized API handler will be able to tell the difference and add or omit the authorization key in the Google Provider options accordingly.
Update #2: I can provide extra parameters to signIn
Turns out the signIn
function can accept additional parameters as a third argument.
This allows me to separate the login from the permissions, but now the API calls I'm making to Google Ads are failing with "PERMISSION_DENIED: Request had insufficient authentication scopes.", despite having successfully granted permissions.
I can confirm the permissions are granted in my Google account, but when I look at the Prisma database managed by next-auth, I don't see the new scope in my account.
Perhaps I can use the signIn
callback to make sure the scope is updated? My problem there is that the account I get as a parameter to my signIn
callback has the old scope…
To separate the login and grant flows, I had to:
signIn
method without arguments for a regular sign insignIn('google', undefined, { scope: googleAdsScope })
signIn
callbackSee my repro repo for the full, working code.