Skip to content

Commit 1732254

Browse files
committed
fix(auth): repair password reset redirect and recovery callback
- Route passed Codevs to the ungated /home/account-settings so non-admins reach the change-password screen instead of being bounced to /home - Verify the recovery token with type 'recovery' and redirect to sign-in when verification fails - Guard the PKCE code branch so existing approved users are not demoted to the Applicant role/status
1 parent de38474 commit 1732254

2 files changed

Lines changed: 37 additions & 3 deletions

File tree

‎apps/codebility/app/auth/callback/route.ts‎

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,17 @@ export async function GET(request: Request) {
1616
const cookieStore = await cookies();
1717
const supabase = await createClientServerComponent();
1818

19-
await supabase.auth.verifyOtp({ token_hash: tokenHash, type: "email" });
19+
// Recovery links carry a recovery token, so verify with the "recovery" OTP type.
20+
const { error } = await supabase.auth.verifyOtp({
21+
token_hash: tokenHash,
22+
type: "recovery",
23+
});
24+
25+
// Honor verification failures: send the user to a clear sign-in/error state
26+
// instead of redirecting to the destination page unauthenticated.
27+
if (error) {
28+
return NextResponse.redirect(new URL("/auth/sign-in", origin));
29+
}
2030

2131
if (redirectTo) {
2232
return NextResponse.redirect(`${origin}${redirectTo}`);
@@ -51,7 +61,31 @@ export async function GET(request: Request) {
5161
throw new Error("User not found or not authenticated");
5262
}
5363

54-
// Update the codev table with the Applicant role ID and application status
64+
// Determine whether this is a genuine first-time signup or an existing
65+
// approved user delivered through the recovery/sign-in `code` path.
66+
const { data: existingCodev } = await supabase
67+
.from("codev")
68+
.select("role_id, application_status")
69+
.eq("id", user.id)
70+
.single();
71+
72+
const isExistingApprovedUser =
73+
!!existingCodev &&
74+
((existingCodev.role_id != null &&
75+
existingCodev.role_id !== applicantRoleId) ||
76+
(existingCodev.application_status != null &&
77+
existingCodev.application_status !== "applying"));
78+
79+
if (isExistingApprovedUser) {
80+
// Existing approved user: establish the session WITHOUT mutating
81+
// role_id/application_status, and route to their normal destination.
82+
await supabase.auth.exchangeCodeForSession(code);
83+
return NextResponse.redirect(
84+
new URL(redirectTo ?? "/home", requestUrl.origin),
85+
);
86+
}
87+
88+
// Genuine first-time signup: assign the Applicant role and status.
5589
const { error: updateError } = await supabase
5690
.from("codev")
5791
.update({

‎apps/codebility/app/auth/password-reset/action.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const resetUserPassword = async (email: string) => {
2828
}
2929

3030
const url = data.availability_status === "passed"
31-
? `${origin}/auth/callback?redirect_to=/home/settings/account-settings`
31+
? `${origin}/auth/callback?redirect_to=/home/account-settings`
3232
: `${origin}/auth/callback?redirect_to=/applicant/account-settings`;
3333

3434
/*

0 commit comments

Comments
 (0)