Skip to content

Account management

Endpoints under /auth/account/* let authenticated users manage their profile, password, email, and account lifecycle.

Method Path Auth Request Response
GET /auth/account/profile yes {id, email, name?, image?}
PUT /auth/account/profile yes {name?, image?} (at least one) updated profile; 400 if both empty
POST /auth/account/change-password yes {current_password, new_password} {message}
POST /auth/account/change-email yes {new_email, password} {message}
GET /auth/account/confirm-email-change (token) ?token=... {message}
DELETE /auth/account yes {password} {message}

Change password

Verifies current_password against the stored Argon2 hash, then stores the new hash, then deletes all of the user's refresh_jti tokens, forcing every other session to re-authenticate. on_password_reset hook fires (the same hook is reused for reset-password). Requires token_adapter for the JTI revocation; without it the refresh JTIs cannot be revoked.

Change email

  1. Verify password. 400 Password is incorrect on mismatch.
  2. Normalize new email; reject if in use. 409 Email is already in use.
  3. Create a one-time token of type "email_change", TTL 30 minutes, with raw_data={"email": new_email}.
  4. Email is sent to the new address (not the current one), with a link {base_url}/auth/account/confirm-email-change?token=....
  5. User clicks → GET /auth/account/confirm-email-change?token=... consumes the token, validates raw_data.email, sets email and email_verified=True on the user, then deletes remaining email_change tokens and all refresh_jti tokens (forcing re-auth).

Requires token_adapter.

Delete account

Verifies password, deletes refresh_jti tokens, deletes all user sessions via session_adapter (if set), and soft-deletes the user (is_active=False). In cookie mode, the auth cookies are cleared.

Common mistakes

  • Email is sent to the new address, not the old one — this is intentional (the new owner of the new email must consent). If your user expects a notification at the old address, add it in an on_oauth_link-style hook (none exists for email change — needs maintainer clarification).
  • DELETE /auth/account soft-deletes — the row remains in the DB with is_active=False. adapter.get_user_by_email will still match it; subsequent /auth/register with the same email returns 409. Hard-delete via the adapter if you need true removal.