Skip to content

Send a dead confirmation link back into the app, not to raw JSON - #52

Merged
yt314 merged 1 commit into
mainfrom
confirm-link-dead-end
Sep 19, 2026
Merged

yt314 merged 1 commit into
mainfrom
confirm-link-dead-end

Conversation

@yt314

@yt314 yt314 commented Sep 19, 2026 •

Copy link
Copy Markdown
Owner

I walked the new-teacher onboarding end to end for the first time: register → confirmation email → confirm → sign in. Registration and the email are fine. The link's failure path is not.

Before

--- expired / wrong token ---
HTTP 400  content-type: application/json; charset=utf-8
body: {"message":"אימות נכשל או שפג תוקף הקישור."}

--- link that lost its token ---
HTTP 400
body: {"type":"https://tools.ietf.org/html/rfc9110#section-15.5.1","title":"One or more
       validation errors occurred.","status":400,"errors":{"userId":["The userId field
       is required."]},"traceId":"00-fdc90c87…"}

The browser renders that as one bare line on a white page. No way back to the app, no way to ask for a new link — at step one of using the product. The second case is worse: she gets an English stack-trace-shaped blob.

Neither reason is exotic. A link older than its lifetime does it, and so does a mail client that wraps a long URL and cuts it.

The success path already redirected into the app. Only the failures didn't.

After

--- bad token ---                 HTTP 302  ->  http://localhost:4200/login?confirmed=0
--- truncated link (no token) ---  HTTP 302  ->  http://localhost:4200/login?confirmed=0
--- valid link ---                 HTTP 302  ->  http://localhost:4200/login?confirmed=1

And on the screen she lands on:

LANDED ON:     /login?confirmed=0
SCREEN SAYS:   … התחברות  מורות, הורים ותלמידים — כולם נכנסים כאן.
               קישור האימות אינו תקף או שפג תוקפו. אפשר להזין כאן את כתובת המייל ולקבל קישור חדש
RESEND BUTTON? 1

The resend itself was already there — it just only ran after a sign-in blocked on an unverified address, so it only ever knew the address from that attempt. It now also takes the one being typed into the form:

EMPTY CLICK SAYS: יש להזין את כתובת המייל כדי לשלוח קישור חדש.
AFTER RESEND:     נשלח אליה מייל אימות חדש.

And a real email goes out — not just a reassuring message. Counted in the mail sink for a fresh, still-unverified account:

emails after register: 1
emails after resend  : 2
second link: HTTP 302 -> http://localhost:4200/login?confirmed=1

So the recovery actually recovers.

Checked and left alone

  • Clicking a valid link twice still succeeds both times — ASP.NET confirms an already-confirmed user again — so an inbox click after the fact does not send her to the failure screen.
  • Resending for an address that is already verified sends nothing and still shows the same "אם הכתובת אינה מאומתת עדיין…" wording. That is deliberate: it is what keeps the screen from disclosing whether an address is registered.

Testing

  • dotnet test — 250 passing, including three new cases in AuthFlowTests: a token that is not hers, a link that lost its token, and a link with nothing left on it.
  • npx ng build and npx vitest run — clean, 30 passing.

Demo data untouched — the two accounts registered for this walkthrough were deleted, and the teacher list is back to the original four.

The confirmation email is the first thing a new teacher does. Clicking a
link that no longer works answered with a JSON body, which the browser
renders as one bare line of Hebrew on a white page:

    {"message":"אימות נכשל או שפג תוקף הקישור."}

No way back, no way to ask for a new link, at step one of using the product.
The reasons are ordinary: a link older than its lifetime, or one a mail
client wrapped and cut in half.

The success path already redirected into the app; failures now do the same,
to /login?confirmed=0. The login screen explains what happened and offers to
send a new link — reusing the resend that was already there for a sign-in
blocked on an unverified address. That path only knew the address from a
failed sign-in, so it now also takes the one being typed into the form, and
says so if the field is empty.

Adds three cases to AuthFlowTests: a token that is not hers, a link that
lost its token, and a link with nothing left on it.
@vercel

vercel Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
talmidon Ready Ready Preview Sep 19, 2026 8:51pm UTC

@yt314
yt314 merged commit 2d0b942 into main Sep 19, 2026
7 checks passed

This branch was successfully deployed

1 active deployment
Preview — b8d7ba28 Deployed Sep 19, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant