Avoid OAuth pitfalls in Lovable. Learn to add login options and apply best practices with proper redirects for secure auth flows.

Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
OAuth breaks in Lovable when the app's redirect_uri doesn't exactly match the URI registered with the OAuth provider. In Lovable this happens often because preview URLs are ephemeral (different host), you can accidentally hardcode a local URL, or the app uses a different scheme/path (missing trailing slash, http vs https). Providers reject the exchange when the redirect doesn't exactly match, producing redirect_mismatch or invalid\_grant errors.
Paste each prompt into Lovable chat so Lovable can edit code and guide you to set secrets and provider console entries.
// Prompt A: Replace hardcoded redirect with env-driven value
// Edit file: src/server/auth/oauth.ts (or the file where you create the OAuth redirect)
// Instruction to Lovable:
// 1) Open src/server/auth/oauth.ts
// 2) Replace any hardcoded redirect URI with process.env.OAUTH_REDIRECT
// 3) Export/return the redirectUri so callback handlers use it
//
// Provide the updated file content below and ensure it reads process.env.OAUTH_REDIRECT.
// Prompt B: Create README comment and environment secret names
// Edit file: README.md (project root) - add a short section "OAuth redirect setup for Lovable"
// Instruction to Lovable:
// 1) Append a section that tells developers to set these secrets in Lovable's Secrets UI:
// - OAUTH_CLIENT_ID
// - OAUTH_CLIENT_SECRET
// - OAUTH_REDIRECT (full absolute URL used by the provider, e.g., https://<preview-or-prod>/auth/callback)
// 2) Include a note that preview URLs change and both preview and published URLs must be added to the provider console.
// Prompt C: Secrets UI guidance for the user (action outside code but Lovable should show instructions)
// Instruction to Lovable:
// Show the user step-by-step how to open the Lovable Secrets panel and add:
// - OAUTH_CLIENT_ID: (paste client id)
// - OAUTH_CLIENT_SECRET: (paste client secret)
// - OAUTH_REDIRECT: use the exact full callback URL for the environment they will test (copy from Preview or Published URL + /auth/callback)
// Also instruct user to add that same exact URL in their OAuth provider's Allowed Redirect URIs (this is outside Lovable: provider web dashboard).
Testing steps inside Lovable: After applying the code change and adding secrets, click Preview, copy the preview URL, confirm OAUTH\_REDIRECT matches that preview URL in both Lovable Secrets and your provider console, then test the sign-in flow. Publish after you add the published domain to the provider's redirect list.
This prompt helps an AI assistant understand your setup and guide you through the fix step by step, without assuming technical knowledge.
Yes — you can add OAuth providers by: adding provider buttons in the UI, storing provider client_id/client_secret in Lovable’s Secrets UI, creating server-side OAuth start and callback endpoints inside the Lovable app (so the secret never goes to the browser), and wiring the frontend to redirect to those endpoints. Use Preview to test and Publish (or GitHub export if you need terminal work). Below are Lovable-ready prompts you can paste into the project chat that instruct Lovable to implement the pieces (Next.js fallback provided; Lovable should adapt if your framework differs).
Paste this into Lovable chat so it edits files:
// Detect the app framework. If it's Next.js, create API routes.
// If it's a different framework, implement equivalent server endpoints and tell me which files you changed.
// For Next.js: create src/pages/api/auth/[provider].ts
// This endpoint builds and redirects to the provider authorization URL using secrets.
Create file src/pages/api/auth/[provider].ts with this content:
// Start OAuth flow: redirect to provider's auth URL
import { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { provider } = req.query
// // Add providers here. Example: google
if (provider !== 'google') {
return res.status(400).send('unsupported provider')
}
const clientId = process.env.OAUTH_GOOGLE_CLIENT_ID
const redirectUri = process.env.OAUTH_REDIRECT_URI // set in Lovable Secrets
const scope = encodeURIComponent('openid email profile')
const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${scope}&access_type=offline&prompt=consent`
return res.redirect(authUrl)
}
// For Next.js: create src/pages/api/auth/callback.ts
// This endpoint exchanges code for tokens server-side and returns a short-lived session cookie or JSON.
Create file src/pages/api/auth/callback.ts with this content:
// OAuth callback: exchange code for tokens securely
import { NextApiRequest, NextApiResponse } from 'next'
import fetch from 'node-fetch' // Lovable will add dependency if needed via GitHub export; otherwise use global fetch if available
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { code, provider } = req.query
if (!code || provider !== 'google') return res.status(400).send('missing code or provider')
const tokenRes = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
code: String(code),
client_id: String(process.env.OAUTH_GOOGLE_CLIENT_ID),
client_secret: String(process.env.OAUTH_GOOGLE_CLIENT_SECRET),
redirect_uri: String(process.env.OAUTH_REDIRECT_URI),
grant_type: 'authorization_code'
})
})
const tokenJson = await tokenRes.json()
// // At this point, create a session for the user and set a secure cookie (or return token to client)
// // For demo: return token JSON (in production create a server session)
return res.status(200).json(tokenJson)
}
Paste this into Lovable chat so it creates/updates UI files:
// Create a simple React component for OAuth buttons and mount it on the existing login page.
// Create file src/components/OAuthButtons.tsx
Create file src/components/OAuthButtons.tsx with this content:
import React from 'react'
export default function OAuthButtons() {
// // Replace or extend providers as implemented server-side
const providers = ['google']
return (
<div>
{providers.map((p) => (
// // clicking triggers redirect to our server start endpoint
<button key={p} onClick={() => { window.location.href = `/api/auth/${p}` }}>
Continue with {p[0].toUpperCase() + p.slice(1)}
</button>
))}
</div>
)
}
// Update your login page to import and render this component.
// If your login page is src/pages/login.tsx or src/pages/index.tsx, insert inside the auth area:
// import OAuthButtons from 'src/components/OAuthButtons'
// <OAuthButtons />
Paste this into Lovable chat to add guidance and ensure code uses these names:
// Add the following secrets in Lovable Cloud -> Secrets (use exact names):
// OAUTH_GOOGLE_CLIENT_ID
// OAUTH_GOOGLE_CLIENT_SECRET
// OAUTH_REDIRECT_URI
// Set OAUTH_REDIRECT_URI to your app's published callback URL, e.g.:
// https://your-published-domain.com/api/auth/callback
// // For Preview testing, you can temporarily set it to the Preview URL + /api/auth/callback.
// // Make sure the provider console (Google) has the exact same redirect URI registered.
Paste this into Lovable chat:
// Use Preview to test the flow: click "Continue with Google" in the previewed login page.
// After verifying, Publish the app and update provider console redirect URI to the published domain (if you used preview earlier).
// If node-fetch or another dependency is flagged and you'd rather install it locally, export to GitHub and run npm/yarn install & deploy outside Lovable. Label that step "outside Lovable (terminal required)".
Store secrets in Lovable Secrets, do all token exchanges and validation on the server side, use PKCE + state for client-side flows, keep scopes minimal, set HttpOnly Secure SameSite cookies and rotate refresh tokens, never log secrets, and test in Preview before exporting to GitHub if you need terminal-only changes.
Best practice: Put OAuth client IDs, client secrets, and an encryption key only in Lovable’s Secrets UI — never in source files. Reference them via process.env in server code.
// Create src/server/config.ts
// // Read secrets from process.env (Lovable injects Secrets into process.env)
export const OAUTH_CLIENT_ID = process.env.OAUTH_CLIENT_ID!
export const OAUTH_CLIENT_SECRET = process.env.OAUTH_CLIENT_SECRET!
export const TOKEN_ENCRYPTION_KEY = process.env.TOKEN_ENCRYPTION_KEY!
export const OAUTH_PROVIDER_JWKS_URL = process.env.OAUTH_PROVIDER_JWKS_URL!
Best practice: Generate PKCE code_verifier & code_challenge on the client and use a cryptographically-random state. Store only the state in a short-lived HttpOnly cookie performed by server helper endpoints; do the real token exchange server-side.
// Create src/utils/pkce.ts
// // helper functions for PKCE and state generation
export function generateCodeVerifier(){ /* // implement secure random base64-url string */ }
export function generateCodeChallenge(verifier){ /* // implement SHA256 then base64-url */ }
export function generateState(){ /* // secure random string */ }
Best practice: Implement server API routes that perform code -> token exchange, validate ID tokens (via JWKS if OIDC), fetch userinfo server-side, and persist only encrypted tokens or session IDs.
// Create src/server/api/oauth/callback.ts
// // validate state cookie, exchange code for tokens, validate ID token via JWKS,
// // encrypt tokens with TOKEN_ENCRYPTION_KEY and create a server session
Best practice: Use HttpOnly, Secure, SameSite=strict cookies for session IDs; set short lifetimes for access tokens, rotate refresh tokens, and rotate session IDs on privilege changes.
// Create src/server/session.ts
// // setCookie(response, { httpOnly: true, secure: true, sameSite: 'strict', maxAge: ... })
// // rotateSession(response, oldSessionId) -> newSessionId
Best practice: Request the minimal scopes needed, prefer short-lived access tokens, implement refresh-token rotation server-side, and revoke old refresh tokens after use.
// Create src/server/api/oauth/refresh.ts
// // read encrypted refresh token, call provider token endpoint to refresh,
// // replace stored token with new encrypted token, revoke old refresh token if provider supports it
Best practice: Never log client secrets, tokens, or raw authorization codes. Log only correlation IDs and non-secret error codes. Capture and surface user-facing errors gracefully.
// Create src/server/logging.ts
// // function safeLog(ctx, message, meta) { // redact token-like keys in meta before logging }
Best practice: Test OAuth flows in Lovable Preview using Secrets UI values. When you need to run migrations, add provider configuration that requires terminal/infra changes, export/sync to GitHub and make those infra changes outside Lovable (outside Lovable — terminal required).
From startups to enterprises and everything in between, see for yourself our incredible impact.
Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We’ll discuss your project and provide a custom quote at no cost.