Google OAuth Integration
Configure Google login inside a TypeScript codebase, with step-by-step route endpoints configurations.
Outline↓
Google OAuth Integration
Why Google OAuth is used
Google OAuth is one of the most widely adopted identity verification standards on the web. It provides:
- Low Friction: Users can log in with a single click, boosting user conversion rates.
- Verified Identity: Google handles bot detection and account verification, ensuring you deal with genuine email profiles.
- Security Standards: Features like Multi-Factor Authentication (MFA) and account recovery are managed by Google.
Implementing this requires exchanging authorization codes for identity credentials (OpenID Connect ID Tokens).
Mental Model
Think of Google OAuth as Hotel Card Key Verification.
- Traditional Login: You buy a house and install a custom lock. You have to craft physical keys (passwords) and manage who holds them.
- OAuth Login: You check into a hotel. Instead of giving you a permanent key to the building, the receptionist verifies your ID card, registers your stay, and gives you a temporary Key Card (Access/ID Token). This card only unlocks your specific room (email scope) and automatically deactivates when you check out (token expiry).
Core Specifications
- Why it exists: It was created based on OpenID Connect (OIDC) standards built on top of OAuth 2.0 to offer a unified, federated user identity and authentication framework.
- What problem it solves: It eliminates user sign-up drop-offs with single-click authentication while validating emails and outsourcing password storage, MFA, and account recovery to Google.
- How it works internally: The user grants access on Google's consent screen. Google redirects back with an authorization code. The application backend exchanges this code via a POST request for an Access Token and a cryptographically signed ID Token (JWT), validating its signature using Google's dynamic public keys.
- When to use it: Use it in consumer SaaS apps, booking apps, and client portals where zero-friction sign-ups and verified email identities are essential.
- How it is used in real projects: Production web portals extract the OIDC profile data from verified ID tokens, synchronizing it into their local user databases via transactional upserts and initializing default dashboards.
Codebase Integration
Here is a step-by-step guide to integrating Google Login via OpenID Connect (OIDC) APIs.
Step 1: Configure credentials in Google Cloud Console
- Go to Google Cloud Console > API & Services > Credentials.
- Create an OAuth Client ID for a Web Application.
- Set your Authorized JavaScript origins (e.g.
http://localhost:3000). - Set your Authorized redirect URIs (e.g.
http://localhost:3000/api/auth/google/callback). - Copy your Client ID and Client Secret.
Step 2: Configure Environment Credentials
Open your .env file and save the variables.
# .env (Environment config)
GOOGLE_CLIENT_ID="your_google_client_id_here"
GOOGLE_CLIENT_SECRET="your_google_client_secret_here"
Step 3: Redirect Client to Google Consent Screen
Create a route to compile parameters and redirect the browser to Google.
// filepath: src/app/api/auth/google/route.ts
// Purpose: Redirect user to Google OAuth endpoint.
import { NextResponse } from 'next/server';
export async function GET() {
const rootUrl = 'https://accounts.google.com/o/oauth2/v2/auth';
const options = {
redirect_uri: 'http://localhost:3000/api/auth/google/callback',
client_id: process.env.GOOGLE_CLIENT_ID || '',
access_type: 'offline', // Request refresh tokens
response_type: 'code',
prompt: 'consent',
scope: [
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email',
].join(' '),
};
const qs = new URLSearchParams(options).toString();
return NextResponse.redirect(`${rootUrl}?${qs}`);
}
Step 4: Handle the Token Callback Endpoint
Examine the authorization code parameter and fetch the Google profile.
// filepath: src/app/api/auth/google/callback/route.ts
// Purpose: Exchange authorization code, read profile info, and establish session cookie.
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const code = searchParams.get('code');
if (!code) {
return NextResponse.json({ error: 'Auth code not provided' }, { status: 400 });
}
try {
// 1. Request OAuth Token from Google token service
const response = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
code,
client_id: process.env.GOOGLE_CLIENT_ID || '',
client_secret: process.env.GOOGLE_CLIENT_SECRET || '',
redirect_uri: 'http://localhost:3000/api/auth/google/callback',
grant_type: 'authorization_code',
}),
});
const data = await response.json();
if (!data.id_token) {
return NextResponse.json({ error: 'OAuth exchange returned no ID Token' }, { status: 401 });
}
// 2. Fetch User Info using Google Access Token
const userInfoResponse = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
headers: {
Authorization: `Bearer ${data.access_token}`,
},
});
const userInfo = await userInfoResponse.json();
// 3. Set secure session token cookie containing Google login email details
const redirectResponse = NextResponse.redirect(new URL('/dashboard', request.url));
redirectResponse.cookies.set('session_token', data.access_token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
maxAge: 60 * 60, // 1 hour
});
return redirectResponse;
} catch (error) {
console.error('Google Callback Error:', error);
return NextResponse.json({ error: 'Google authentication failed' }, { status: 500 });
}
}
Practical Project Use Cases
1. User Registration Schema Synchronization
When a user logs in via Google, your database schema must reconcile the returning OAuth identity. If the user already exists, you should refresh their profile image and last-login timestamps. If they are a new sign-up, you must atomically create a user record and initialize default data (like a personal workspace folder).
- Real-World Example: We handle the profile sync inside a database transaction right after validating the Google callback credentials, ensuring database operations execute reliably.
// filepath: src/services/userSyncService.ts
// Purpose: Upsert user details from Google profile details and compile default workspace schemas.
import { db } from '@/lib/db';
interface GoogleProfile {
id: string;
email: string;
name: string;
picture: string;
}
export async function synchronizeGoogleUser(profile: GoogleProfile) {
// Use a transaction to ensure user creation and default workspace setup succeed together
return await db.$transaction(async (tx) => {
// 1. Upsert user records keyed by the verified Google email
const user = await tx.user.upsert({
where: { email: profile.email },
update: {
name: profile.name,
avatarUrl: profile.picture,
lastActiveAt: new Date(),
},
create: {
email: profile.email,
name: profile.name,
avatarUrl: profile.picture,
provider: 'GOOGLE',
providerId: profile.id,
},
});
// 2. Check if the user needs a default workspace setup (e.g. on new signups)
const existingWorkspaces = await tx.workspace.findFirst({
where: { ownerId: user.id },
});
if (!existingWorkspaces) {
await tx.workspace.create({
data: {
name: `${profile.name || 'My'}'s Workspace`,
ownerId: user.id,
},
});
}
return user;
});
}
2. Live Calendar Event Syncing
For productivity or booking applications (like Calendly), Google OAuth tokens are requested with https://www.googleapis.com/auth/calendar.events scopes, letting your application query and append calendar invites when a customer books a meeting.
- Real-World Example: Using the persistent offline refresh token, a backend worker runs cron cycles to query the Google Calendar API, checking for conflicts before booking a demo meeting on your system.
Common Pitfalls
1. Inconsistent Callback URL Configuration
If the callback URI in your code (http://localhost:3000/api/auth/google/callback) differs by even a single slash from the redirect URI registered in Google Console, Google will block the transaction with a redirect_uri_mismatch error.
- Fix: Copy and paste the redirect URLs exactly as they are defined in your Google Cloud dashboard.
2. Not Verifying ID Tokens correctly
In high-security codebases, decoding tokens locally without validation is dangerous.
- Fix: Use Google OAuth SDKs or fetch Google's public JSON Web Keys (JWKs) at
https://www.googleapis.com/oauth2/v3/certsto verify the cryptographic signature of returning ID tokens before writing session profiles to the database.
Interview Questions
What is the difference between Access Tokens and ID Tokens?
An Access Token is an authorization credential used by the application to request API data from Google servers on behalf of the user. An ID Token is an identity credential (a signed JWT) that contains claims about the authenticated user (like email, profile name, and picture), verifying their log in session.
Summary
- Scope: Requests specific profile permissions using scopes.
- OIDC: Leverages OpenID Connect to verify identity profiles securely.
- Verification: Checks certificates dynamically when high security is needed.