feat: social auth account linking
This commit is contained in:
@@ -21,11 +21,22 @@ import { auth, type User } from "@/lib/auth";
|
||||
* After a successful login/signup/logout the provider re-fetches /auth/me
|
||||
* to keep state in sync with the cookie.
|
||||
*/
|
||||
/**
|
||||
* LogInResult is either a completed session (regular case) or a signal
|
||||
* that the BFF wants a one-time code before completing the login. Callers
|
||||
* should branch on `kind` and, for `otp_required`, present an OTP field
|
||||
* and call `verifyLoginOTP`.
|
||||
*/
|
||||
export type LogInResult =
|
||||
| { kind: "session"; user: User }
|
||||
| { kind: "otp_required" };
|
||||
|
||||
type AuthContextValue = {
|
||||
user: User | null;
|
||||
loading: boolean;
|
||||
signUp: (email: string, password: string, name: string) => Promise<User>;
|
||||
logIn: (email: string, password: string) => Promise<User>;
|
||||
logIn: (email: string, password: string) => Promise<LogInResult>;
|
||||
verifyLoginOTP: (email: string, password: string, otp: string) => Promise<User>;
|
||||
logOut: () => Promise<void>;
|
||||
refresh: () => Promise<void>;
|
||||
/** Replace the user state without a network round-trip (after profile edit). */
|
||||
@@ -58,19 +69,42 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
}, []);
|
||||
|
||||
const logIn = useCallback(async (email: string, password: string) => {
|
||||
const u = await auth.logIn(email, password);
|
||||
setUser(u);
|
||||
return u;
|
||||
const res = await auth.logIn(email, password);
|
||||
if (res.kind === "session") {
|
||||
setUser(res.user);
|
||||
}
|
||||
// For `otp_required` we deliberately leave `user` null so the rest of
|
||||
// the app keeps showing the signed-out state until VerifyLoginOTP
|
||||
// completes.
|
||||
return res;
|
||||
}, []);
|
||||
|
||||
const verifyLoginOTP = useCallback(
|
||||
async (email: string, password: string, otp: string) => {
|
||||
const u = await auth.verifyLoginOTP(email, password, otp);
|
||||
setUser(u);
|
||||
return u;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const logOut = useCallback(async () => {
|
||||
await auth.logOut();
|
||||
setUser(null);
|
||||
}, []);
|
||||
|
||||
const value = useMemo<AuthContextValue>(
|
||||
() => ({ user, loading, signUp, logIn, logOut, refresh, setUser }),
|
||||
[user, loading, signUp, logIn, logOut, refresh],
|
||||
() => ({
|
||||
user,
|
||||
loading,
|
||||
signUp,
|
||||
logIn,
|
||||
verifyLoginOTP,
|
||||
logOut,
|
||||
refresh,
|
||||
setUser,
|
||||
}),
|
||||
[user, loading, signUp, logIn, verifyLoginOTP, logOut, refresh],
|
||||
);
|
||||
|
||||
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
||||
|
||||
Reference in New Issue
Block a user