feat: social auth account linking

This commit is contained in:
gosangam
2026-06-02 22:55:09 +05:30
parent 086f1dd8aa
commit ec67ddf852
6 changed files with 675 additions and 177 deletions
+44 -3
View File
@@ -83,10 +83,43 @@ export const auth = {
body: JSON.stringify({ email, password, name }),
}),
logIn: (email: string, password: string) =>
authFetch<User>("/auth/login", {
/**
* Submits email/password. Three outcomes:
* - kind: "session" → fully signed in; auth-provider sets the user.
* - kind: "otp_required" → account has been unverified for >30 days;
* a 6-digit code was emailed. Caller must show an OTP form and call
* `verifyLoginOTP(email, password, otp)` to complete sign-in.
* Throws AuthError on credential / server errors.
*/
logIn: async (
email: string,
password: string,
): Promise<
| { kind: "session"; user: User }
| { kind: "otp_required" }
> => {
const data = await authFetch<User | { otp_required: true }>(
"/auth/login",
{
method: "POST",
body: JSON.stringify({ email, password }),
},
);
if (data && typeof data === "object" && "otp_required" in data) {
return { kind: "otp_required" };
}
return { kind: "session", user: data as User };
},
/**
* Completes a login that was paused by the OTP gate. Re-checks the
* password (the OTP alone isn't enough — defence in depth), validates
* the code, marks the email verified, and sets the session cookie.
*/
verifyLoginOTP: (email: string, password: string, otp: string) =>
authFetch<User>("/auth/verify-login-otp", {
method: "POST",
body: JSON.stringify({ email, password }),
body: JSON.stringify({ email, password, otp }),
}),
logOut: () => authFetch<{ ok: boolean }>("/auth/logout", { method: "POST" }),
@@ -133,6 +166,14 @@ export const auth = {
body: JSON.stringify({ email }),
}),
/**
* Returns the list of OAuth provider names already linked to the
* signed-in user (e.g. `["google", "facebook"]`). The settings page
* uses this to flip per-provider rows between "Connect" / "Connected".
*/
linkedProviders: () =>
authFetch<{ providers: string[] }>("/auth/linked-providers"),
/**
* Replaces the signed-in user's password. The BFF verifies the current
* password, hashes the new one, and re-issues the session cookie so this