Skip to content

idp: HTML form for self-service account deletion at /idp/account/delete #392

Description

@melvincarvalho

Follow-up from #391 (closed #352).

The DELETE /idp/account endpoint shipped, but there's no human-friendly UI to drive it — operators today have to do the two-curl dance:

TOKEN=$(curl -sX POST .../idp/credentials -d '{"email":"…","password":"…"}' | jq -r .access_token)
curl -sX DELETE .../idp/account -H "Authorization: Bearer $TOKEN" \
  -d '{"currentPassword":"…","purgeData":true}'

For end users (especially anyone testing key-add flows in #386 Phase B who needs a way to recreate from a borked profile), this needs an HTML form.

Proposed shape

/idp/account/delete — public HTML page (matches the existing unauthenticated /idp landing and /idp/register pages). Asks for credentials at submission time rather than relying on session state.

Form fields

  • Username or email — identifies the account
  • Current password — re-entry as proof of possession
  • Type your username to confirm — destructive-action UX guard (typical pattern)
  • ☐ Also delete my pod data — checkbox; off by default. Maps to purgeData: true.
  • Submit — submit triggers the destructive action

Warning copy

"This permanently deletes account <username> and revokes all sessions and tokens. It cannot be undone. Pod data is preserved unless you tick the box below."

Two implementation options

A — server-side login+delete shim (recommended)

New handler that accepts POST /idp/account/delete form-encoded with username/password/purgeData. Internally: validate credentials, call deleteAccount if match, return success/failure HTML. No JS required, accessibility-first.

POST /idp/account/delete  (application/x-www-form-urlencoded)
  username=...&currentPassword=...&purgeData=on&confirm=...

Pros: works without JavaScript, no client-side token juggling, matches the existing form-submit pattern of /idp/register. Single round-trip.
Cons: blurs the "two-step: identify, then act" model the DELETE endpoint enforces. But functionally identical — user is proving credentials at delete time.

B — client-side JS

Form's submit handler does fetch /idp/credentials (login → token) then fetch DELETE /idp/account (delete using token). Calls the existing endpoints directly, no new server-side handler.

Pros: re-uses the existing endpoint contract verbatim; nothing new server-side.
Cons: requires JS (no graceful degrade); two round-trips; password is in JS scope briefly.

Single-user mode

Same 403 as the endpoint — operator path stays the CLI. Form should detect this server-side and render "Account deletion via HTTP is disabled in single-user mode" with a link to docs explaining the rationale.

Acceptance

  • /idp/account/delete returns 200 HTML
  • Form submission with valid credentials deletes the account; subsequent login fails 401
  • Form submission with wrong password redirects back to the form with an error message; account untouched
  • purgeData=on checkbox produces the same on-disk effect as the JSON purgeData: true (uses account.podName, not the lowercased username — see idp: self-service DELETE /idp/account endpoint (#352) #391 pass 2)
  • Single-user mode shows the disabled message instead of the form
  • Tests cover happy path + failure modes (mirror test/idp-delete-account.test.js)

Refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions