import { json, redirect, type LoaderFunctionArgs, type MetaFunction } from '@remix-run/cloudflare'; import { useLoaderData } from '@remix-run/react'; import { AuthError, createUserSession, exchangeCodeForToken, fetchGitHubUser, verifyState, } from '~/lib/auth/github-oauth.server'; import BackgroundRays from '~/components/ui/BackgroundRays'; export const meta: MetaFunction = () => { return [ { title: 'Authenticating...' }, { name: 'description', content: 'Completing GitHub authentication' }, ]; }; export async function loader({ request, context }: LoaderFunctionArgs) { // Get URL parameters const url = new URL(request.url); const code = url.searchParams.get('code'); const state = url.searchParams.get('state'); const error = url.searchParams.get('error'); const errorDescription = url.searchParams.get('error_description'); // Get the redirect URL from state or default to home const redirectTo = url.searchParams.get('redirectTo') || '/'; // Handle GitHub OAuth errors if (error) { return json({ success: false, error: error, errorDescription: errorDescription || 'An error occurred during authentication', redirectTo: '/', }); } // Validate required parameters if (!code || !state) { const errorParams = new URLSearchParams([ ['error', 'invalid_request'], ['error_description', 'Missing required parameters'] ]); return redirect(`/auth/login?${errorParams}`); } try { console.log('=== CALLBACK FLOW DEBUG ==='); console.log('Step 1: Starting state verification...'); // Verify state parameter to prevent CSRF attacks const cookieHeader = await verifyState(request, state, context); console.log('Step 1: ✅ State verification successful'); console.log('Step 2: Starting token exchange...'); // Exchange authorization code for access token const { accessToken } = await exchangeCodeForToken(code, state, context); console.log('Step 2: ✅ Token exchange successful'); console.log('Step 3: Starting user data fetch...'); // Fetch user data from GitHub API const user = await fetchGitHubUser(accessToken); console.log('Step 3: ✅ User data fetch successful'); console.log('Step 4: Creating user session...'); // Create user session and redirect const result = await createUserSession( request, { accessToken, user, }, redirectTo, context ); console.log('Step 4: ✅ User session created successfully'); console.log('============================'); return result; } catch (error) { console.error('=== AUTHENTICATION FAILURE ==='); console.error('Error type:', error.constructor.name); console.error('Error message:', error.message); console.error('Error stack:', error.stack); console.error('==============================='); let errorMessage = 'An unexpected error occurred during authentication'; let errorCode = 'server_error'; if (error instanceof AuthError) { errorMessage = error.message; errorCode = 'auth_error'; } // For authentication failures, redirect to login with error params const errorParams = new URLSearchParams([ ['error', errorCode], ['error_description', errorMessage] ]); return redirect(`/auth/login?${errorParams}`); } } export default function AuthCallback() { const data = useLoaderData(); // Only render the component if we have error data // On successful auth, the server will redirect immediately if (data && 'success' in data && !data.success) { return (

Authentication Failed

{data.errorDescription}

Redirecting you back in a moment...

); } // Loading state return (

Authenticating...

Completing your sign-in with GitHub

); }