Auth Issues
Troubleshoot authentication problems — OAuth, sessions, magic links, and more.
OAuth callback URL mismatch
Symptom: After clicking "Sign in with Google/GitHub," you get a redirect error like "redirect_uri_mismatch."
Cause: The callback URL registered with the OAuth provider doesn't match what Better Auth generates.
Fix:
The callback URL format is:
{BETTER_AUTH_URL}/api/auth/callback/{provider}
- Check your
BETTER_AUTH_URL:
# Development
BETTER_AUTH_URL="http://localhost:3000"
# Production
BETTER_AUTH_URL="https://yourdomain.com"
- Update the callback URL in each provider:
Google Cloud Console:
http://localhost:3000/api/auth/callback/google
https://yourdomain.com/api/auth/callback/google
GitHub Developer Settings:
http://localhost:3000/api/auth/callback/github
https://yourdomain.com/api/auth/callback/github
- Make sure there are no trailing slashes —
/callback/googlenot/callback/google/
AUTH_SECRET not set
Symptom: App crashes with AUTH_SECRET is not set or sessions don't work.
Cause: The AUTH_SECRET environment variable is missing or empty.
Fix:
Generate a secure secret:
openssl rand -base64 32
Add it to .env.local:
AUTH_SECRET="your-generated-secret-here"
Important: use a different secret for each environment (development, staging, production). If you change the secret, all existing sessions become invalid.
Session not persisting after login
Symptom: You log in successfully but are immediately logged out, or refreshing the page loses the session.
Cause: Cookie configuration issues.
Fix:
-
Check your URL: Make sure you're accessing the app at
http://localhost:3000, nothttp://127.0.0.1:3000. Cookies are domain-specific. -
Check BETTER_AUTH_URL: This must match the URL you're accessing:
BETTER_AUTH_URL="http://localhost:3000"
-
Clear cookies: Open DevTools > Application > Cookies, clear all cookies for localhost, and try again.
-
Check for HTTPS issues: In production, cookies require HTTPS. Make sure your domain has SSL configured (Vercel does this automatically).
-
Check session expiration: If sessions expire too quickly, increase the duration:
export const auth = betterAuth({
session: {
expiresIn: 60 * 60 * 24 * 30, // 30 days
},
});
Magic link email not arriving
Symptom: User requests a magic link but never receives the email.
Cause: Email service not configured, domain not verified, or email going to spam.
Fix:
- Check Resend is configured:
RESEND_API_KEY="re_your-api-key"
EMAIL_FROM="noreply@yourdomain.com"
-
Check the Resend dashboard: Go to resend.com/emails and look for the email in the logs. You'll see if it was sent, delivered, or bounced.
-
Check spam/junk folder: Magic link emails sometimes get flagged, especially with unverified domains.
-
Verify your domain: In Resend dashboard > Domains, make sure your sending domain is verified. Without verification, emails may not deliver or go to spam.
-
Check the server logs: Look for error messages from the email sending function.
"Invalid credentials" on login
Symptom: Login fails with "Invalid credentials" even with the correct email.
Cause: Wrong password, or the account was created with OAuth (no password set).
Fix:
-
If the user registered with Google/GitHub, they don't have a password. They need to use the same OAuth provider to log in.
-
Check the
accountstable in your database to see which providers are linked:
SELECT provider FROM accounts WHERE user_id = 'the-user-id';
- If the user wants to set a password, implement a "Set Password" flow in the settings page.
Google OAuth "Access blocked" error
Symptom: Google shows "Access blocked: This app's request is invalid" or "Error 403: access_denied."
Cause: OAuth consent screen not configured or app needs verification.
Fix:
- Go to Google Cloud Console
- Configure the OAuth consent screen:
- App name, support email, developer contact
- Add your domain to "Authorized domains"
- For development, set the app to "Testing" and add your email as a test user
- For production with 100+ users, submit for Google verification
GitHub OAuth "Application suspended" error
Symptom: GitHub shows "Application suspended" when trying to log in.
Cause: The GitHub OAuth app was suspended, or the client credentials are wrong.
Fix:
- Go to GitHub Developer Settings > OAuth Apps
- Verify the app exists and is not suspended
- Regenerate the client secret if needed
- Update
GITHUB_CLIENT_IDandGITHUB_CLIENT_SECRETin.env.local
CORS errors on auth endpoints
Symptom: Browser console shows Access-Control-Allow-Origin errors when making auth requests.
Cause: Frontend making requests to a different origin than the auth server.
Fix:
- Make sure
BETTER_AUTH_URLmatches the URL your frontend uses - If your frontend and API are on different domains, configure CORS in Better Auth:
export const auth = betterAuth({
trustedOrigins: [
"http://localhost:3000",
"https://yourdomain.com",
],
});
- In most KitRocket setups, frontend and API are on the same origin, so CORS isn't needed.
Users can access dashboard without logging in
Symptom: Protected pages are accessible without authentication.
Cause: Auth middleware not running or not configured correctly.
Fix:
- Check that middleware exists and covers the right paths:
export { authMiddleware as default } from "@/lib/auth/middleware";
export const config = {
matcher: ["/dashboard/:path*", "/settings/:path*", "/billing/:path*"],
};
- Verify the middleware checks the session:
export async function authMiddleware(request: NextRequest) {
const session = await auth.api.getSession({
headers: request.headers,
});
if (!session) {
return NextResponse.redirect(new URL("/login", request.url));
}
return NextResponse.next();
}
- Clear your browser cookies and test in an incognito window to rule out cached sessions.