Your login form looks fine, email and password seem correct – yet Supabase Auth responds with:
AuthApiError: Invalid login credentials
Or in the Network tab: 400 with error_description: "Invalid login credentials". Here are the most common causes and the fixes that reliably worked for me.
The Problem: What "Invalid login credentials" Really Means
For security reasons Supabase does not tell you whether the email or the password is wrong. That single message covers several cases:
- Wrong password or a typo in the email
- User does not exist (yet) in this project
- Email not confirmed yet (
Enable email confirmations) - Wrong project / wrong keys in the client
- User created via OAuth, but login attempted with password
The Solution: Narrow Down the Cause
Step 1: Check the User in the Dashboard
Under Authentication → Users, search for the email:
- No row → sign-up failed or different project
- Row without confirmation → confirmation still pending
- Provider only
google/github→ password login will not work
Step 2: Call Sign-in Correctly
const { data, error } = await supabase.auth.signInWithPassword({
email: email.trim().toLowerCase(),
password,
})
if (error) {
console.error(error.message, error.status)
// "Invalid login credentials" → see checklist below
}
Use trim() and keep email casing consistent between sign-up and sign-in.
Step 3: Email Confirmation
If confirmations are enabled and the user is unconfirmed, login can fail depending on your settings. For debugging, temporarily disable confirmations or confirm the user in the dashboard:
-- Local/dev only: confirm a user manually
UPDATE auth.users
SET email_confirmed_at = now()
WHERE email = 'test@example.com';
Step 4: Verify Project URL and Keys
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
)
Mixed projects (staging vs production) are a classic: sign-up lands in project A, login hits project B.
Common Mistakes
- signUp instead of signIn: a second sign-up with the same email feels like a login failure.
- Whitespace in inputs: mobile autofill often adds trailing spaces.
- Identity linking: user registered with Google, then tries email/password.
- Custom SMTP / redirect URLs: confirmation mail never arrives → account stays unconfirmed.
Complete Login Example with Clear Errors
async function login(email, password) {
const { data, error } = await supabase.auth.signInWithPassword({
email: email.trim().toLowerCase(),
password,
})
if (error) {
if (error.message === 'Invalid login credentials') {
return {
ok: false,
hint: 'Check email/password, confirmation, and auth provider in the dashboard.',
}
}
if (error.message.includes('Email not confirmed')) {
return { ok: false, hint: 'Confirm the email or unlock the user in the dashboard.' }
}
return { ok: false, hint: error.message }
}
return { ok: true, session: data.session }
}
Troubleshooting Checklist
- ✅ User present under Authentication → Users?
- ✅
email_confirmed_atset (if confirmations are on)? - ✅ Login method matches provider (password vs OAuth)?
- ✅ URL + anon key belong to the same project as the user?
- ✅ Email trimmed / password free of autofill artifacts?
Conclusion
Invalid login credentials is intentionally vague. With a dashboard check, correct signInWithPassword, a confirmed email, and the right project keys, you usually find the cause in a few minutes.
Additional Resources
- permission denied for table (42501)
- PGRST116: multiple (or no) rows returned
- Supabase Storage File Upload Guide
- How to query users table?
- Supabase: infinite recursion detected in policy
- Supabase Edge Functions: Invalid JWT / 401
- Supabase Storage 403 RLS on upload
- Supabase Edge Functions CORS Error Fix
- Fix RLS insert errors
- Supabase Auth password docs
Still seeing the message with the correct password? Leave a comment – often it is confirmation or the wrong provider.
Comments