Skip to main content
DelightBridge uses Google OAuth 2.0 for two distinct purposes:
  1. App Authentication - Users sign in with their Google account (NextAuth)
  2. Gmail Service Connection - Connecting Gmail accounts to sync and send emails (Gmail API)
Both flows use the same OAuth client credentials (GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET) but require different redirect URIs and scopes.

Google Cloud Console Setup

1

Create a Google Cloud project

Go to Google Cloud Console and sign in.Click Select a projectNew Project
  • Project name: DelightBridge (or your preferred name)
  • Organization: Leave default or select your organization
Click Create.
2

Enable Gmail API

In your new project, go to APIs & ServicesLibrarySearch for “Gmail API” and click on it.Click Enable.
The Gmail API is required for syncing messages and sending emails from DelightBridge.
3

Configure OAuth consent screen

Go to APIs & ServicesOAuth consent screen

Choose user type:

  • Internal - Only for Google Workspace organizations (users in your domain)
  • External - Anyone with a Google account
For most use cases, choose External, then click Create.

Fill in app information:

App information:
  • App name: DelightBridge
  • User support email: Your email address
  • App logo: (Optional) Upload your logo
App domain (optional):
  • Application home page: https://your-project.vercel.app
  • Privacy policy: (Optional)
  • Terms of service: (Optional)
Authorized domains: Add your deployment domain:
vercel.app
If using custom domain:
delightroom.com
Developer contact information:
  • Enter your email address
Click Save and Continue.
4

Configure scopes

On the Scopes page, click Add or Remove Scopes.Add these scopes:

For user authentication (NextAuth):

  • openid - Required for OpenID Connect
  • email - User email address
  • profile - User profile information

For Gmail API access:

  • https://www.googleapis.com/auth/gmail.readonly - Read Gmail messages
  • https://www.googleapis.com/auth/gmail.send - Send Gmail messages
You can paste the full scope URLs in the filter box to find them quickly.
Click UpdateSave and Continue.
5

Add test users (External apps only)

If you chose External user type, your app starts in testing mode.Add test users who can access the app:
  • Click Add Users
  • Enter email addresses (one per line)
  • Click Add
Click Save and Continue.
While in testing mode, only listed test users can sign in. To allow anyone, you must publish the app (requires verification for sensitive scopes).
6

Create OAuth credentials

Go to APIs & ServicesCredentialsClick Create CredentialsOAuth client IDApplication type: Web applicationName: DelightBridge Web ClientAuthorized JavaScript origins (optional):
http://localhost:3000
https://your-project.vercel.app
Add your custom domain if applicable:
https://bridge.delightroom.com
Authorized redirect URIs:You need four redirect URIs - two for local development and two for production.

Local development:

http://localhost:3000/api/auth/callback/google
http://localhost:3000/api/services/oauth/callback

Production (Vercel):

https://your-project.vercel.app/api/auth/callback/google
https://your-project.vercel.app/api/services/oauth/callback

Production (Custom domain, if applicable):

https://bridge.delightroom.com/api/auth/callback/google
https://bridge.delightroom.com/api/services/oauth/callback
Replace your-project.vercel.app with your actual Vercel domain and bridge.delightroom.com with your custom domain.
Click Create.
7

Copy credentials

After creation, a dialog shows your credentials:
  • Client ID: 123456789-abcdefghijklmnop.apps.googleusercontent.com
  • Client Secret: GOCSPX-abcd1234efgh5678ijkl
Copy both values and save them securely.Click OK.

Understanding OAuth Flows

DelightBridge uses two separate OAuth flows with different purposes.

Flow 1: App Authentication (User Sign-In)

Purpose: Authenticate users who access DelightBridge. Flow:
  1. User clicks “Sign in with Google” on /login page
  2. Redirects to Google OAuth consent screen
  3. User authorizes (grants openid, email, profile scopes)
  4. Google redirects to /api/auth/callback/google
  5. NextAuth creates session, checks user allowlist (ADMIN_EMAILS or workspace_members)
  6. User redirected to DelightBridge main app
Redirect URI:
http://localhost:3000/api/auth/callback/google
https://your-project.vercel.app/api/auth/callback/google
Scopes:
  • openid
  • email
  • profile
Implementation:
  • Handled by NextAuth in auth.ts
  • Uses Google Provider from next-auth/providers/google

Flow 2: Gmail Service Connection

Purpose: Connect a Gmail account to DelightBridge for syncing and sending emails. Flow:
  1. Admin clicks “서비스 추가 + 연결” in Settings
  2. Creates service in database
  3. Redirects to GET /api/services/:id/connect
  4. Redirects to Google OAuth consent screen
  5. User authorizes (grants Gmail API scopes: gmail.readonly, gmail.send)
  6. Google redirects to /api/services/oauth/callback
  7. Backend exchanges code for tokens (access_token, refresh_token)
  8. Tokens saved to database (gmail_accounts table)
  9. User’s Gmail email automatically synced to service
  10. User redirected back to DelightBridge
Redirect URI:
http://localhost:3000/api/services/oauth/callback
https://your-project.vercel.app/api/services/oauth/callback
Scopes:
  • https://www.googleapis.com/auth/gmail.readonly - Read Gmail messages
  • https://www.googleapis.com/auth/gmail.send - Send Gmail messages
Implementation:
  • Start: GET /api/services/:id/connect (builds OAuth URL)
  • Callback: GET /api/services/oauth/callback (exchanges code for tokens)

Required OAuth Scopes

App Authentication Scopes

ScopePurpose
openidOpenID Connect authentication
emailAccess user’s email address
profileAccess user’s name and profile picture
These are non-sensitive scopes and don’t require app verification.

Gmail API Scopes

ScopePurpose
https://www.googleapis.com/auth/gmail.readonlyRead all Gmail messages, threads, and labels
https://www.googleapis.com/auth/gmail.sendSend emails on behalf of the user
These are sensitive scopes. For production use beyond test users, your app requires Google verification.
Testing Mode Limitation: While your OAuth consent screen is in testing mode, only users you explicitly add as test users can authorize Gmail access. For broader access, you must publish the app (requires verification).

Redirect URI Configuration

DelightBridge requires two redirect URIs per environment.

Why two redirect URIs?

  1. /api/auth/callback/google - NextAuth callback for user sign-in
  2. /api/services/oauth/callback - Gmail service connection callback

Complete redirect URI list

For local development + production deployment:
http://localhost:3000/api/auth/callback/google
http://localhost:3000/api/services/oauth/callback
https://your-project.vercel.app/api/auth/callback/google
https://your-project.vercel.app/api/services/oauth/callback
If using custom domain, add:
https://bridge.delightroom.com/api/auth/callback/google
https://bridge.delightroom.com/api/services/oauth/callback
You can have multiple redirect URIs in a single OAuth client. Add all environments upfront.

Add Environment Variables

After creating OAuth credentials, add them to your environment.

Local development (.env.local)

GOOGLE_CLIENT_ID=123456789-abcdefghijklmnop.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-abcd1234efgh5678ijkl

Production (Vercel)

Go to Vercel dashboard → Your project → SettingsEnvironment Variables Add:
  • Key: GOOGLE_CLIENT_ID Value: 123456789-abcdefghijklmnop.apps.googleusercontent.com
  • Key: GOOGLE_CLIENT_SECRET Value: GOCSPX-abcd1234efgh5678ijkl
Select All Environments (Production, Preview, Development).
Never commit GOOGLE_CLIENT_SECRET to version control. Keep it in environment variables only.

Testing OAuth Flows

Test user sign-in

  1. Start development server:
pnpm dev
  1. Go to http://localhost:3000
  2. You should be redirected to /login
  3. Click Sign in with Google
  4. Authorize with Google (use email in ADMIN_EMAILS or added to workspace_members)
  5. After authorization, you should be redirected to DelightBridge main app
Expected behavior:
  • User created in users table
  • Session established
  • Access granted to DelightBridge

Test Gmail service connection

  1. Sign in to DelightBridge as admin
  2. Click Settings (gear icon in sidebar)
  3. Go to 서비스 관리 tab
  4. Click 서비스 추가 + 연결
  5. Enter service name (e.g., “Noji Support”) and click 추가
  6. You’re redirected to Google OAuth consent screen
  7. Authorize Gmail scopes (gmail.readonly, gmail.send)
  8. After authorization, you’re redirected back to DelightBridge
Expected behavior:
  • Service created with connected Gmail email
  • OAuth tokens saved to database
  • Service appears in sidebar
  • Ready to sync Gmail messages

Publishing Your App (Optional)

While in testing mode, only test users can authorize the app. To allow anyone:
1

Prepare for verification

Google requires verification for apps using sensitive scopes like Gmail API.Requirements:
  • Privacy policy URL
  • Terms of service URL
  • App homepage URL
  • YouTube demo video showing OAuth flow
  • Detailed justification for each scope
2

Submit for verification

Go to OAuth consent screen → Click Publish AppGoogle reviews your app (may take several weeks).
3

After approval

Your app is publicly available - any Google user can authorize it.
For internal tools, you may not need to publish. Keep the app in testing mode and add all team members as test users.

Troubleshooting

”Error 400: redirect_uri_mismatch”

The redirect URI in your request doesn’t match any configured in Google Cloud Console. Solution:
  1. Check exact URL in error message
  2. Go to Google Cloud Console → Credentials → Your OAuth client
  3. Add the exact URL to Authorized redirect URIs
  4. Save and retry (may take a few minutes to propagate)
Common mistakes:
  • Missing trailing slash
  • http vs https
  • localhost vs 127.0.0.1
  • Wrong port number

”Error 403: access_denied” or “This app is blocked”

User is not authorized to access the app. Solutions: For user sign-in:
  • Add user email to ADMIN_EMAILS environment variable, OR
  • Add user to workspace_members table via Settings → 권한 관리
For testing mode apps:
  • Add user as test user in OAuth consent screen
  • Or publish the app (requires verification)

“Error 401: invalid_client”

GOOGLE_CLIENT_ID or GOOGLE_CLIENT_SECRET is incorrect. Solution:
  1. Go to Google Cloud Console → Credentials
  2. Copy Client ID and Client Secret again
  3. Update environment variables
  4. Restart dev server or redeploy to Vercel

”Error 400: invalid_grant” when refreshing tokens

Refresh token is invalid or expired. Causes:
  • User revoked access
  • Token not saved correctly
  • Over 6 months since last use (Google expires refresh tokens)
Solution: Reconnect the Gmail service:
  1. Go to Settings → 서비스 관리
  2. Delete and recreate the service
  3. Complete OAuth flow again

Gmail API quota exceeded

You’ve hit Google’s daily API quota (default: 1 billion quota units/day). Solution:
  • Reduce CRON_SYNC_MAX_ACCOUNTS to sync fewer accounts per run
  • Increase cron interval in vercel.json (e.g., every 15 minutes instead of 5)
  • Request quota increase in Google Cloud Console

Security Best Practices

  • Never commit OAuth credentials - Use environment variables only
  • Use different credentials for development and production
  • Rotate secrets regularly - Create new Client Secret periodically
  • Monitor OAuth consent screen - Check for unusual authorization patterns
  • Limit test users - Only add necessary users in testing mode
  • Enable 2FA - Require two-factor auth for admin accounts
  • Review authorized apps - Users can revoke access at myaccount.google.com/permissions

Build docs developers (and LLMs) love