feat(auth): sync OAuth provider tokens to backend via NextAuth session

Wire the Google/Facebook OAuth callback flow end-to-end so the provider's id_token (Google) and access_token (Facebook) captured by NextAuth are forwarded to the backend in exchange for business tokens:

- Extend the NextAuth config with jwt/session callbacks that surface `account.id_token` / `account.access_token` to the client during first sign-in
- Add an `OAuthSessionSync` bridge mounted inside `RootProviders` that listens to `useSession()` and dispatches new `AuthGoogleSyncSubmitted` / `AuthFacebookSyncSubmitted` events
- Add corresponding actors in the auth XState machine that call `authRepository.googleLogin` / `facebookLogin`, persisting the backend's `LoginResponse` through the existing repository path

This keeps all authentication orchestrated by the auth state machine while preserving NextAuth's OAuth redirect UX.
This commit is contained in:
2026-06-11 12:59:23 +08:00
parent b50191ed50
commit 0c63b7dee4
6 changed files with 203 additions and 2 deletions
+22
View File
@@ -33,6 +33,28 @@ const handler = NextAuth({
pages: {
signIn: "/auth",
},
// 把 OAuth provider 的 token 塞进 NextAuth session,供前端取用:
// - Google: account.id_token → 调后端 /api/auth/google-login 换业务 token
// - Facebook: account.access_token → 调后端 /api/auth/facebook-login
// 仅在**首次 sign-in** 时把 `account` 注入到 JWT;后续请求 account=undefined
// (由 NextAuth 控制),所以下面的 `if (account)` 守卫是必要的。
callbacks: {
async jwt({ token, account }) {
if (account) {
token.provider = account.provider;
token.idToken = account.id_token;
token.accessToken = account.access_token;
}
return token;
},
async session({ session, token }) {
// 暴露给 `useSession()` —— 仅 client-side 派发 sync 事件时使用,不落 localStorage
session.provider = (token.provider as "google" | "facebook" | undefined) ?? undefined;
session.idToken = (token.idToken as string | undefined) ?? undefined;
session.accessToken = (token.accessToken as string | undefined) ?? undefined;
return session;
},
},
// 显式允许从请求头(X-Forwarded-Host)推断 host;消除 v4 [NEXTAUTH_URL] 警告
// 生产部署在反向代理后(nginx / cloudflare)必须开
// @ts-expect-error: `trustHost` 不在 v4.24.x 的 AuthOptions 类型里,但运行时支持