Skip to content

Commit 60eddac

Browse files
committed
fix reset password flow
1 parent df392d6 commit 60eddac

5 files changed

Lines changed: 38 additions & 4 deletions

File tree

docs/supabase-local-first.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,14 @@ If `.env.local` still points at `https://mfnaqdyunuafbwukbbyr.supabase.co`, the
130130

131131
Peels intentionally uses the `54331`-`54334` range so you can run it alongside other Supabase projects that still use the default local ports.
132132

133+
### Local auth emails
134+
135+
Supabase captures local auth emails in Mailpit instead of sending them to a real inbox. After `npm run supabase:start`, open `http://127.0.0.1:54334` to inspect password reset, magic-link, invite, and email-change messages generated by the local stack.
136+
137+
The local stack uses Supabase's built-in auth email templates unless the Send Email Auth Hook is configured locally. The Peels custom auth email implementation lives in `supabase/functions/send-email-for-auth-action`, but that function is only used when Supabase Auth is configured to call it as the `send_email` hook. Hosted environments configure that in Supabase Auth Hooks; the default local `config.toml` path keeps Mailpit simple and uses the built-in templates.
138+
139+
For reset-password testing, use the reset link from Mailpit and keep the app running at `http://127.0.0.1:3000`. `supabase/config.toml` allow-lists `http://127.0.0.1:3000/**` and `http://localhost:3000/**` so Supabase can redirect through `/auth/complete` before landing on `/profile/reset-password`.
140+
133141
### Demo accounts
134142

135143
Both local demo accounts use the password `peels-demo-password`.

e2e/auth.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,25 @@ test("sign-in preserves a safe redirect_to", async ({ page }) => {
3131
await expect(page).toHaveURL(/\/profile$/);
3232
});
3333

34+
test("password reset success page renders for signed-in users", async ({
35+
page,
36+
}) => {
37+
const successMessage =
38+
"Your password has been updated. Let’s get back to composting!";
39+
40+
await signIn(page, {
41+
email: HOST_EMAIL,
42+
redirectTo: `/profile/reset-password?success=${encodeURIComponent(
43+
successMessage
44+
)}`,
45+
});
46+
47+
await expect(
48+
page.getByRole("heading", { name: "Password updated" })
49+
).toBeVisible();
50+
await expect(page.getByText(successMessage)).toBeVisible();
51+
});
52+
3453
test("sign-in normalises unsafe redirect_to values", async ({ page }) => {
3554
await signIn(page, {
3655
email: HOST_EMAIL,

src/app/(forms)/profile/reset-password/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default async function ResetPassword(props: {
3030
<Form as="container">
3131
<p>{searchParams.success}</p>
3232
{/* User is authenticated at this point so we can redirect them to a protected route */}
33-
<Button href="/profile" variant="primary">
33+
<Button href="/profile" variant="primary" width="full">
3434
{t("Actions.backToPeels")}
3535
</Button>
3636
</Form>

src/components/Button/Button.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,8 @@ const Button = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>(
408408
if (isLink) {
409409
const linkProps = getLinkButtonProps(restProps as LinkButtonRestProps);
410410
const rel = resolveExternalRel(linkProps.target, linkProps.rel);
411+
const clickProps =
412+
isDisabled || onClick ? { onClick: handleLinkClick } : {};
411413

412414
return (
413415
<StyledLink
@@ -421,7 +423,7 @@ const Button = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonProps>(
421423
aria-disabled={isDisabled || undefined}
422424
aria-busy={isLoading || undefined}
423425
data-button-width={allProps.width ?? "contained"}
424-
onClick={handleLinkClick}
426+
{...clickProps}
425427
{...linkProps}
426428
rel={rel}
427429
>

supabase/config.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,13 @@ enabled = true
111111
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
112112
# in emails.
113113
site_url = "http://127.0.0.1:3000"
114-
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
115-
additional_redirect_urls = ["https://127.0.0.1:3000"]
114+
# A list of URLs that auth providers are permitted to redirect to post authentication.
115+
# Local auth emails use broad localhost wildcards so app flows can redirect through
116+
# /auth/complete and any other local callback paths used during development.
117+
additional_redirect_urls = [
118+
"http://127.0.0.1:3000/**",
119+
"http://localhost:3000/**",
120+
]
116121
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week).
117122
jwt_expiry = 3600
118123
# If disabled, the refresh token will never expire.

0 commit comments

Comments
 (0)