"use client"; import { useEffect, useState } from "react"; import { useRouter, useSearchParams } from "next/navigation"; import { toast } from "@nice/ui/components/sonner"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@nice/ui/components/card"; import { Button } from "@nice/ui/components/button"; import { client } from "@/lib/auth-client"; export default function BetterAuthCallbackPage() { const router = useRouter(); const searchParams = useSearchParams(); const [status, setStatus] = useState<'loading' | 'success' | 'error'>('loading'); const [message, setMessage] = useState('正在处理认证回调...'); const [authData, setAuthData] = useState(null); const [session, setSession] = useState(null); useEffect(() => { const handleCallback = async () => { try { console.log('开始处理 Better Auth 回调...'); console.log('当前 URL:', window.location.href); // 获取URL参数 const code = searchParams.get('code'); const error = searchParams.get('error'); const errorDescription = searchParams.get('error_description'); const state = searchParams.get('state'); const sessionState = searchParams.get('session_state'); console.log('回调参数:', { code, error, errorDescription, state, sessionState, fullURL: window.location.href }); // 检查是否有错误 if (error) { let errorMsg = error; if (error === 'oauth_code_verification_failed') { errorMsg = 'OAuth授权码验证失败。可能的原因包括:\n1. 授权码已过期\n2. 授权码已被使用\n3. 客户端配置不匹配\n4. PKCE验证失败'; } else if (error === 'account_not_linked') { errorMsg = '账户未关联。请先创建用户账户或登录现有账户。'; } throw new Error(errorDescription || errorMsg); } // 如果没有授权码,说明可能是直接访问回调页面 if (!code) { throw new Error('未收到授权码。请从测试页面启动 OAuth 流程。'); } setMessage('收到授权码,正在完成认证流程...'); // 等待 Better Auth 处理回调 // Better Auth 会自动处理从 URL 参数中的授权码交换令牌 let attempts = 0; const maxAttempts = 10; const checkSession = async (): Promise => { attempts++; console.log(`尝试检查会话,第 ${attempts} 次`); try { const sessionResult = await client.getSession(); console.log('会话检查结果:', sessionResult); if (sessionResult.data) { return sessionResult.data; } else if (attempts < maxAttempts) { // 等待一段时间再重试 await new Promise(resolve => setTimeout(resolve, 500)); return checkSession(); } else { throw new Error('认证完成但未建立会话'); } } catch (error) { console.error(`会话检查失败 (尝试 ${attempts}):`, error); if (attempts < maxAttempts) { await new Promise(resolve => setTimeout(resolve, 500)); return checkSession(); } else { throw error; } } }; const finalSession = await checkSession(); setStatus('success'); setMessage('OAuth2 认证成功!已建立用户会话。'); setSession(finalSession); setAuthData({ code, state, sessionState, timestamp: new Date().toISOString(), user: finalSession.user }); toast.success('OAuth2 认证成功!'); } catch (error) { console.error('认证回调失败:', error); setStatus('error'); setMessage(error instanceof Error ? error.message : '认证失败'); toast.error(`认证失败: ${error instanceof Error ? error.message : '未知错误'}`); } }; // 给页面一点时间加载,然后处理回调 const timeoutId = setTimeout(handleCallback, 100); return () => clearTimeout(timeoutId); }, [searchParams]); const handleBackToTest = () => { router.push('/test'); }; const handleTryAgain = () => { router.push('/test'); }; return (
{status === 'loading' && (
)} {status === 'success' && (
)} {status === 'error' && (
)}
{status === 'loading' && 'Better Auth 回调处理中'} {status === 'success' && '认证成功'} {status === 'error' && '认证失败'} {message}
{authData && (

认证信息:

                                    {JSON.stringify(authData, null, 2)}
                                
)} {session && (

用户会话:

用户 ID: {session.user?.id}
邮箱: {session.user?.email}
姓名: {session.user?.name}
会话 ID: {session.id}
)}
{status === 'success' && ( )} {status === 'error' && ( )}

说明:

  • 这是 Better Auth Generic OAuth 的回调页面
  • 用于处理 OAuth2/OIDC 认证流程的回调
  • 成功时会显示收到的授权码和用户会话信息
  • Better Auth 会自动处理令牌交换和会话创建
  • 如果出现 "account_not_linked" 错误,请先登录一个用户账户
); }