- App Authentication - Users sign in with their Google account (NextAuth)
- Gmail Service Connection - Connecting Gmail accounts to sync and send emails (Gmail API)
GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET) but require different redirect URIs and scopes.
Google Cloud Console Setup
Create a Google Cloud project
Go to Google Cloud Console and sign in.Click Select a project → New Project
- Project name:
DelightBridge(or your preferred name) - Organization: Leave default or select your organization
Enable Gmail API
In your new project, go to APIs & Services → LibrarySearch for “Gmail API” and click on it.Click Enable.
The Gmail API is required for syncing messages and sending emails from DelightBridge.
Configure OAuth consent screen
Go to APIs & Services → OAuth consent screenIf using custom domain:Developer contact information:
Choose user type:
- Internal - Only for Google Workspace organizations (users in your domain)
- External - Anyone with a Google account
Fill in app information:
App information:- App name:
DelightBridge - User support email: Your email address
- App logo: (Optional) Upload your logo
- Application home page:
https://your-project.vercel.app - Privacy policy: (Optional)
- Terms of service: (Optional)
- Enter your email address
Configure scopes
On the Scopes page, click Add or Remove Scopes.Add these scopes:Click Update → Save and Continue.
For user authentication (NextAuth):
openid- Required for OpenID Connectemail- User email addressprofile- User profile information
For Gmail API access:
https://www.googleapis.com/auth/gmail.readonly- Read Gmail messageshttps://www.googleapis.com/auth/gmail.send- Send Gmail messages
You can paste the full scope URLs in the filter box to find them quickly.
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
Create OAuth credentials
Go to APIs & Services → CredentialsClick Create Credentials → OAuth client IDApplication type: Web applicationName: Add your custom domain if applicable:Authorized redirect URIs:You need four redirect URIs - two for local development and two for production.Click Create.
DelightBridge Web ClientAuthorized JavaScript origins (optional):Local development:
Production (Vercel):
Production (Custom domain, if applicable):
Replace
your-project.vercel.app with your actual Vercel domain and bridge.delightroom.com with your custom domain.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:- User clicks “Sign in with Google” on
/loginpage - Redirects to Google OAuth consent screen
- User authorizes (grants
openid,email,profilescopes) - Google redirects to
/api/auth/callback/google - NextAuth creates session, checks user allowlist (
ADMIN_EMAILSorworkspace_members) - User redirected to DelightBridge main app
openidemailprofile
- 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:- Admin clicks “서비스 추가 + 연결” in Settings
- Creates service in database
- Redirects to
GET /api/services/:id/connect - Redirects to Google OAuth consent screen
- User authorizes (grants Gmail API scopes:
gmail.readonly,gmail.send) - Google redirects to
/api/services/oauth/callback - Backend exchanges code for tokens (
access_token,refresh_token) - Tokens saved to database (
gmail_accountstable) - User’s Gmail email automatically synced to service
- User redirected back to DelightBridge
https://www.googleapis.com/auth/gmail.readonly- Read Gmail messageshttps://www.googleapis.com/auth/gmail.send- Send Gmail messages
- 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
| Scope | Purpose |
|---|---|
openid | OpenID Connect authentication |
email | Access user’s email address |
profile | Access user’s name and profile picture |
Gmail API Scopes
| Scope | Purpose |
|---|---|
https://www.googleapis.com/auth/gmail.readonly | Read all Gmail messages, threads, and labels |
https://www.googleapis.com/auth/gmail.send | Send emails on behalf of the user |
Redirect URI Configuration
DelightBridge requires two redirect URIs per environment.Why two redirect URIs?
/api/auth/callback/google- NextAuth callback for user sign-in/api/services/oauth/callback- Gmail service connection callback
Complete redirect URI list
For local development + production deployment: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)
Production (Vercel)
Go to Vercel dashboard → Your project → Settings → Environment Variables Add:-
Key:
GOOGLE_CLIENT_IDValue:123456789-abcdefghijklmnop.apps.googleusercontent.com -
Key:
GOOGLE_CLIENT_SECRETValue:GOCSPX-abcd1234efgh5678ijkl
Testing OAuth Flows
Test user sign-in
- Start development server:
-
Go to
http://localhost:3000 -
You should be redirected to
/login - Click Sign in with Google
-
Authorize with Google (use email in
ADMIN_EMAILSor added toworkspace_members) - After authorization, you should be redirected to DelightBridge main app
- User created in
userstable - Session established
- Access granted to DelightBridge
Test Gmail service connection
- Sign in to DelightBridge as admin
- Click Settings (gear icon in sidebar)
- Go to 서비스 관리 tab
- Click 서비스 추가 + 연결
- Enter service name (e.g., “Noji Support”) and click 추가
- You’re redirected to Google OAuth consent screen
-
Authorize Gmail scopes (
gmail.readonly,gmail.send) - After authorization, you’re redirected back to DelightBridge
- 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: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
Submit for verification
Go to OAuth consent screen → Click Publish AppGoogle reviews your app (may take several weeks).
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:- Check exact URL in error message
- Go to Google Cloud Console → Credentials → Your OAuth client
- Add the exact URL to Authorized redirect URIs
- Save and retry (may take a few minutes to propagate)
- Missing trailing slash
httpvshttpslocalhostvs127.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_EMAILSenvironment variable, OR - Add user to
workspace_memberstable via Settings → 권한 관리
- 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:
- Go to Google Cloud Console → Credentials
- Copy Client ID and Client Secret again
- Update environment variables
- 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)
- Go to Settings → 서비스 관리
- Delete and recreate the service
- 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_ACCOUNTSto 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