Google Provider
Google Provider
Section titled “Google Provider”Introduction
Section titled “Introduction”The Google provider in Auth.js enables users to authenticate using their Google accounts via OAuth 2.0 and OpenID Connect. This allows “Sign in with Google” functionality in your Next.js application, leveraging Google’s secure authentication infrastructure.
Why we need the Google provider
Section titled “Why we need the Google provider”Google accounts are ubiquitous, making Google login a convenient option for consumer-facing applications. Integrating Google login reduces barriers to entry, increases conversion rates, and provides access to Google’s user data (with consent) for personalization.
Problem statement
Section titled “Problem statement”How do we integrate Google OAuth 2.0 / OpenID Connect authentication into a Next.js application using Auth.js, including setup, configuration, scope management, ID token validation, and handling of user profile data?
Real-world story
Section titled “Real-world story”A productivity SaaS wanted to allow users to quickly start using their service without creating another password. By adding “Sign in with Google” via Auth.js, they increased sign-up completion rates by 35% and reduced support tickets related to forgotten passwords.
Real-world analogy
Section titled “Real-world analogy”Google provider: Like using a federal ID (passport) to prove your identity at various institutions (banks, government offices, airlines) - you present one trusted credential instead of managing separate credentials for each service.
Visual explanation
Section titled “Visual explanation”User clicks "Sign in with Google" ↓Redirect to Google OAuth consent screen ↓User selects account and grants permission ↓Google redirects back with auth code ↓Auth.js exchanges code for tokens ↓Auth.js validates ID token (if OpenID Connect) ↓Auth.js fetches user profile (if needed) ↓Auth.js creates session with user dataMermaid Diagram 1: Google OAuth/OIDC Flow
Section titled “Mermaid Diagram 1: Google OAuth/OIDC Flow”sequenceDiagram participant U as User participant B as Browser participant A as App (Next.js) participant Auth as Auth.js participant G as Google U->>B: Click "Sign in with Google" B->>A: GET /api/auth/signin/google A->>Auth: Initiate Google login Auth->>G: Redirect to accounts.google.com/o/oauth2/v2/auth G-->>B: Google account chooser + consent screen B->>G: Select account + authorize G-->>B: Redirect to callback?code=XXXX&hd=XXXX B->>A: GET /api/auth/callback/google?code=XXXX A->>Auth: Handle callback Auth->>G: POST /oauth2/v4/token (code) G-->>Auth: Tokens (access_token, id_token, expires_in) Auth->>Auth: Validate id_token (signature, aud, iss, exp) Auth->>G: GET /oauth2/v3/userinfo (Bearer access_token) G-->>Auth: User profile (email, name, picture, etc.) Auth->>A: User object A-->>B: Set session cookie + redirectInternal working
Section titled “Internal working”Google provider specifics:
- Supports both OAuth 2.0 and OpenID Connect (when
scopeincludesopenid) - Requires Google Cloud Platform OAuth 2.0 Client ID and Client Secret
- Default scope when using OpenID Connect:
openid email profile - Additional scopes available:
https://www.googleapis.com/auth/calendar,drive,gmail, etc. - Exchange process:
- Redirect user to Google authorization URL with
client_id,redirect_uri,scope,response_type=code,access_type=offline(for refresh tokens),prompt=consent(optional),state - User selects Google account and consents to permissions on accounts.google.com
- Google redirects back to your
redirect_uriwithcodeparameter (andhdfor hosted domain if applicable) - Your server exchanges
codeforaccess_token,id_token, andrefresh_tokenvia POST to Google token endpoint - Auth.js validates the
id_token(signature, aud, iss, exp) if using OpenID Connect - Use
access_tokento fetch user data from Google UserInfo endpoint - Auth.js creates session with user data
- Redirect user to Google authorization URL with
- Automatic handling of:
- State parameter for CSRF protection
- Code exchange for tokens
- ID token validation (when
openidscope present) - User profile fetching via UserInfo endpoint
- Token refresh (if
access_type=offlineand refresh token granted) - Error handling (invalid code, disallowed useragent, etc.)
Step-by-step flow (detailed with OpenID Connect)
Section titled “Step-by-step flow (detailed with OpenID Connect)”- Initiation: User clicks “Sign in with Google” link from
signIn('google') - Redirect: Browser sent to
https://accounts.google.com/o/oauth2/v2/auth?client_id=...&redirect_uri=...&scope=openid%20email%20profile&access_type=offline&response_type=code&prompt=consent&state=... - Account chooser: User selects Google account (if multiple signed in)
- Consent screen: User reviews requested permissions and clicks “Allow”
- Callback: Google redirects to
YOUR_REDIRECT_URI/callback/google?code=LONG_RANDOM_STRING&state=ORIGINAL_STATE&hd=HOSTED_DOMAIN_IF_APPLICABLE - State validation: Auth.js verifies
stateparameter matches original to prevent CSRF - Token exchange: Backend sends POST to
https://oauth2.googleapis.com/tokenwith:codeclient_idclient_secretredirect_urigrant_type=authorization_code
- Token response: Google returns JSON:
{"access_token": "ya29...","expires_in": 3599,"refresh_token": "1//0...","scope": "openid email profile https://www.googleapis.com/auth/calendar.readonly","id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ij...","token_type": "Bearer"}
- ID token validation: Auth.js:
- Retrieves Google’s public keys from
https://www.googleapis.com/oauth2/v3/certs - Validates
id_tokensignature using appropriate key - Checks
iss(issuer) isaccounts.google.comorhttps://accounts.google.com - Checks
aud(audience) matches yourclient_id - Checks
exp(expiration) is in the future - Optionally checks
hd(hosted domain) if restricting to specific G Suite domain
- Retrieves Google’s public keys from
- User profile: Backend GET to
https://openidconnect.googleapis.com/v1/userinfowithAuthorization: Bearer ACCESS_TOKEN - User data: Google returns JSON with
email,name,picture,given_name,family_name,locale, etc. - Profile processing: Auth.js maps Google user fields to standard user object
- Session creation: Auth.js creates JWT or database session with user data
- Cookie setting: Encrypted session cookie set in response
- Redirect: User sent to
callbackUrl(default:/orcallbackUrlfrom signIn)
Implementation
Section titled “Implementation”Basic setup (OpenID Connect)
Section titled “Basic setup (OpenID Connect)”import NextAuth from "next-auth"import GoogleProvider from "next-auth/providers/google"
export const { GET, POST } = NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET, }) ]})With custom scope and profile mapping
Section titled “With custom scope and profile mapping”import NextAuth from "next-auth"import GoogleProvider from "next-auth/providers/google"
export const { GET, POST } = NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET, authorization: { params: { scope: "openid email profile https://www.googleapis.com/auth/calendar.readonly" } }, profile(profile) { return { id: profile.sub, name: profile.name, email: profile.email, image: profile.picture, // Add custom fields from Google profile googleId: profile.sub, googleLocale: profile.locale, googleHd: profile.hd, // hosted domain googleEmailVerified: profile.email_verified, googlePicture: profile.picture, googleGivenName: profile.given_name, googleFamilyName: profile.family_name } } }) ], callbacks: { async jwt({ token, account, profile }) { // Persist Google access token and ID token if needed if (account) { token.accessToken = access_token token.idToken = id_token } return token }, async session({ session, token, user }) { // Send properties to client session.user.accessToken = token.accessToken return session } }})Restrict to specific hosted domain (e.g., company.com)
Section titled “Restrict to specific hosted domain (e.g., company.com)”GoogleProvider({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET, authorization: { params: { scope: "openid email profile", hd: "yourcompany.com" // Optional: pre-select domain } }, // Optional: validate hosted domain in profile profile(profile) { if (profile.hd !== "yourcompany.com") { throw new Error("Access denied: invalid domain") } return { id: profile.sub, name: profile.name, email: profile.email, image: profile.picture } }})Folder structure
Section titled “Folder structure”src/├── app/│ └── api/│ └── [...nextauth]/│ └── route.ts├── lib/│ ├── auth.ts│ └── google.ts (helper for Google API calls)├── components/│ ├── SignInWithGoogle.tsx│ └── GoogleProfileCard.tsx├── pages/│ └── dashboard/│ └── page.tsx (protected route)└── utils/ └── googleApi.tsBest practices
Section titled “Best practices”Scope management:
- Use
openidscope to enable ID token validation (OpenID Connect) - Request
emailandprofilefor basic user information - Add additional scopes only when needed (follow principle of least privilege)
- Common additional scopes:
https://www.googleapis.com/auth/calendar- Calendar accesshttps://www.googleapis.com/auth/drive.file- Drive file accesshttps://www.googleapis.com/auth/gmail.send- Send emailhttps://www.googleapis.com/auth/contacts.readonly- Read contacts
- Combine scopes as space-separated string
- Review and justify each scope in your privacy policy
Security:
- Store Google client secret securely (use secrets manager in production)
- Use different OAuth clients for development and production
- Set authorized JavaScript origins and redirect URIs in Google Cloud Console
- Enable “Allow access to user data” for required APIs
- Consider restricting by hosted domain (
hdparameter) for G Suite - Regularly rotate client secrets
- Monitor Google Cloud audit logs for OAuth activity
- Set appropriate API restrictions (HTTP referrers, IP addresses) if applicable
User experience:
- Use Google’s “Sign in with Google” button guidelines
- Show which account is being used (email/avatar) after login
- Handle multiple account selection gracefully
- Provide way to disconnect Google account
- Explain what data you’re accessing and why
- Offer to sync data periodically if applicable
- Show last login time/location from Google signals (if available)
- Implement graceful handling of suspended/disabled Google accounts
Data handling:
- Cache Google API responses appropriately (respect rate limits and freshness)
- Handle API errors (400, 401, 403, 429, 5xx) gracefully
- Store access token encrypted (Auth.js does this in JWT/database)
- Consider token refresh for long-lived sessions
- Be aware of Google API terms of service and quota limits
- Don’t store sensitive Google data without explicit consent
- Implement data deletion upon user request (GDPR/CCPA compliance)
Common mistakes
Section titled “Common mistakes”- Forgetting to set authorized JavaScript origins and redirect URIs in Google Cloud Console
- Using HTTP instead of HTTPS in redirect URI (Google requires HTTPS for production)
- Missing
openidscope when you want to validate ID token - Not checking
email_verifiedflag from Google profile - Assuming email is always provided (users can have unverified email)
- Forgetting to urlencode redirect URI when constructing auth link manually
- Using the wrong endpoint for Google Workspace vs consumer accounts
- Not updating OAuth client when changing domains
- Assuming profile picture URL is always available (may be empty)
- Not handling users without given_name/family_name (some cultures)
- Missing
access_type=offlinewhen you need refresh tokens - Forgetting to set
prompt=consentto force re-consent (important for scope changes) - Overlooking that Google may return
emailas null for some accounts - Not validating that the
hdclaim matches expected domain if restricting
Security considerations
Section titled “Security considerations”Token security:
- ID tokens are JWTs - validate signature, iss, aud, exp
- Access tokens are bearer tokens - protect like passwords
- Never log or expose ID or access tokens
- Use short-lived access tokens (default 1 hour) with refresh tokens for longevity
- Store tokens encrypted (Auth.js does this in JWT/database)
- Consider token binding to request properties (IP, User-Agent)
- Implement token revocation on logout (revoke refresh token)
- Monitor for leaked tokens in public repositories
Data privacy:
- Only request scopes necessary for your application
- Clearly explain what Google data you’re accessing in your privacy policy
- Allow users to disconnect Google access and delete associated data
- Respect Google’s API Terms of Service and Developer Policies
- Implement data processing agreements if handling EU user data
- Provide option to download/delete Google-derived data
Domain validation:
- When restricting to hosted domain (
hd), validate the claim in ID token - Consider that
hdmay not be present for consumer (@gmail.com) accounts - Implement additional email domain validation if needed
- Be aware of Google Groups and alias email addresses
Dependency security:
- Keep
googleapisnpm package updated if making direct API calls - Audit dependencies for known vulnerabilities
- Use dependency checking tools (npm audit, snyk, etc.)
Performance notes
Section titled “Performance notes”API rate limits:
- Google OAuth 2.0: Generally generous quotas (check specific API)
- Userinfo endpoint: 10,000 requests per 100 seconds per project
- Google Cloud APIs: Vary by service (check console.cloud.google.com/apis/api)
- Implement exponential backoff for 429 responses
- Use conditional requests (If-Modified-Since, ETag) when applicable
- Consider batching requests where supported by Google APIs
- Cache non-sensitive data (user name, email) with appropriate TTL
- Monitor quota usage in Google Cloud Console
Authentication latency:
- OAuth adds network roundtrips (typically 500ms-1.5s+)
- Cache ID token validation keys (JWKS) for 5+ minutes (they rotate infrequently)
- Consider pre-fetching user profile during silent authentication
- Use CDN for static assets; API must origin from server
- Optimize database queries for user lookup/creation
- Use connection pooling for database access
- Implement server-side caching for frequent Google API calls (respecting TTL)
Scaling:
- Google OAuth scales horizontally by design
- Your backend must handle concurrent callback requests
- Consider using Google Identity Toolkit (now Firebase) for alternative approach
- For high-scale applications, evaluate Customer Managed Encryption Keys (CMEK)
- Monitor quota usage and set up alerts for unexpected spikes
Interview questions
Section titled “Interview questions”- What’s the difference between using Google provider with and without
openidscope? - Which endpoint validates the Google ID token?
- What claims are essential to validate in a Google ID token?
- How does Auth.js prevent CSRF attacks in the Google flow?
- Where is the Google access token stored after authentication?
- How would you refresh a Google access token if needed?
- What information is available in the Google UserInfo endpoint?
- How do you request access to Google Calendar or Drive?
- What happens if a user revokes your application’s access in their Google account?
- How do you restrict Google sign-in to specific hosted domain (e.g., company.com)?
-
Which protocol does the Google provider use when
openidscope is included? a) OAuth 2.0 only b) OpenID Connect only c) Both OAuth 2.0 and OpenID Connect d) SAML 2.0 Answer: c -
What is the purpose of the
id_tokenin Google OpenID Connect flow? a) To refresh access tokens b) To authenticate the user (identity token) c) To authorize API access d) To encrypt session data Answer: b -
Which claim in the Google ID token identifies the user? a) aud b) iss c) sub d) hd Answer: c
-
How do you prevent CSRF attacks in Google OAuth flow? a) Using HTTPS only b) Validating the state parameter c) Checking the Referer header d) Using short-lived tokens Answer: b
-
Which endpoint fetches user profile data after token exchange? a) /oauth2/v3/userinfo b) /oauth2/v4/tokeninfo c) / OpenID Connect v1/userinfo d) /plus/v1/people/me Answer: a (or c - both are valid endpoints)
Practice exercise
Section titled “Practice exercise”Set up Google authentication with:
- Create OAuth Client ID in Google Cloud Console
- Add GOOGLE_ID and GOOGLE_SECRET to .env.local
- Configure Google provider with openid email profile scopes
- Add “Sign in with Google” button to your page
- Create a protected route that displays user’s email and profile picture
- Implement logout functionality
- Add error handling for failed authentication
- Test the full flow: login, access protected route, logout
- Verify ID token validation works by tampering with token (should fail)
Debugging experience
Section titled “Debugging experience”“invalid_id_token” error during authentication. Check:
- GOOGLE_ID and GOOGLE_SECRET match exactly from Google Cloud Console
openidscope included in authorization params- No extra spaces in environment variables
- Using correct token endpoint:
https://oauth2.googleapis.com/token - ID token validation: verifyaud matches GOOGLE_ID
- Issuer validation: iss is
accounts.google.comorhttps://accounts.google.com - Token not expired (check exp claim)
- Hosted domain validation (if using hd parameter)
- Clock skew not causing validation failure
- Trying to regenerate client secret in Google Cloud Console
- Verifying that the ID token is actually a JWT (three parts separated by .)
- Checking that the JWKS endpoint is accessible from your server