Skip to content

Commit 982e85c

Browse files
committed
Better login feedback
1 parent 00d81b5 commit 982e85c

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

src/routes/_libraries/login.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ import { FaGithub, FaGoogle } from 'react-icons/fa'
55
import { BrandContextMenu } from '~/components/BrandContextMenu'
66
import { redirect, createFileRoute } from '@tanstack/react-router'
77
import { getCurrentUser } from '~/utils/auth.server'
8+
import { z } from 'zod'
89

910
export const Route = createFileRoute('/_libraries/login')({
1011
component: LoginPage,
12+
validateSearch: z.object({
13+
error: z.string().optional(),
14+
}),
1115
loader: async () => {
1216
// Call server function directly from loader (works in both SSR and client)
1317
const user = await getCurrentUser()
@@ -69,10 +73,23 @@ export function SignInForm() {
6973
}
7074

7175
function LoginPage() {
76+
const { error } = Route.useSearch()
77+
78+
const errorMessages: Record<string, string> = {
79+
oauth_failed: 'Authentication failed. Please try again.',
80+
}
81+
82+
const errorMessage = error ? errorMessages[error] || 'An error occurred. Please try again.' : null
83+
7284
return (
7385
<div className="min-h-screen ">
7486
<div className="container mx-auto px-4 py-16">
7587
<div className="max-w-2xl mx-auto text-center w-fit">
88+
{errorMessage && (
89+
<div className="mb-4 p-4 bg-red-500/10 border border-red-500/20 rounded-lg text-red-600 dark:text-red-400">
90+
{errorMessage}
91+
</div>
92+
)}
7693
<SignInForm />
7794
</div>
7895
</div>

src/routes/api/auth/callback/$provider.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ export const Route = createFileRoute('/api/auth/callback/$provider')({
1919
const error = url.searchParams.get('error')
2020

2121
if (error) {
22-
console.error('[OAuth Callback] OAuth error received')
23-
return Response.redirect(new URL('/login', request.url), 302)
22+
console.error(`[OAuth Callback] OAuth error received: ${error}`)
23+
return Response.redirect(new URL('/login?error=oauth_failed', request.url), 302)
2424
}
2525

2626
if (!code || !state) {
2727
console.error('[OAuth Callback] Missing code or state')
28-
return Response.redirect(new URL('/login', request.url), 302)
28+
return Response.redirect(new URL('/login?error=oauth_failed', request.url), 302)
2929
}
3030

3131
// Validate state from HTTPS-only cookie (CSRF protection)
@@ -36,14 +36,14 @@ export const Route = createFileRoute('/api/auth/callback/$provider')({
3636

3737
if (!stateCookie) {
3838
console.error('[OAuth Callback] No state cookie found')
39-
return Response.redirect(new URL('/login', request.url), 302)
39+
return Response.redirect(new URL('/login?error=oauth_failed', request.url), 302)
4040
}
4141

4242
const cookieState = decodeURIComponent(stateCookie.split('=').slice(1).join('=').trim())
4343

4444
if (cookieState !== state) {
4545
console.error('[OAuth Callback] State mismatch')
46-
return Response.redirect(new URL('/login', request.url), 302)
46+
return Response.redirect(new URL('/login?error=oauth_failed', request.url), 302)
4747
}
4848

4949
// Clear state cookie (one-time use)

0 commit comments

Comments
 (0)