Browser-direct profile and email management

These are SSO POST operations below the browser-direct base. Every body includes selected session handles; every call needs JSON, admitted Origin and a fresh endpoint DPoP proof. The selected session must be active, activated and currently admitted. No caller-supplied member UUID is accepted. These operations need no five-minute reauthentication requirement. Expired access can be renewed once before retrying; a revoked session needs sign-in.

Profile

Relative path Scope Additional input Success
/profile/get profile None sub, display_name, avatar
/profile/update profile Nonempty profile object Same projection after update

Only display_name and avatar are editable. Display name is trimmed, at most 128 Unicode characters. Avatar is a valid HTTPS URL, at most 255 Unicode characters, without userinfo, controls or backslashes. An empty string clears a field; omission preserves it. Unset values return null. Unknown fields and an empty patch are rejected with invalid_request; missing scope is insufficient_scope (403). These updates do not rotate tokens or close sessions.

{"bd_carrier":"<carrier>","bd_session":"<session>","bd_key":"<carrier secret>","profile":{"display_name":"Sample Member","avatar":"https://images.example.org/avatar.png"}}
{"sub":"cccccccc-cccc-4ccc-8ccc-cccccccccccc","display_name":"Sample Member","avatar":"https://images.example.org/avatar.png"}

In the tenant me projection, name remains the system login name, display_name is the editable name, picture reflects avatar, and preferred_username is absent. Profile editing does not rename the login, alter groups or grant manager permissions.

Email operations

All six require the email scope. An address's presence is distinct from verified ownership, active status and primary selection. Adding an address does not send mail automatically or assert ownership.

Relative path Additional input Success
/emails/list None Email view
/emails/add email (valid, trimmed/lowercased, ≤254 bytes) Email view plus email_id
/emails/resend email_id UUID Email view after delivery request
/emails/verify email_id UUID, code six-digit string Email view after proof
/emails/primary email_id UUID Email view with chosen primary
/emails/remove email_id UUID Email view after removal

Every email view contains sub and emails. Rows contain only id, email, status, boolean verified, primary_email, can_send, can_verify, can_make_primary, can_remove, and numeric resend_after seconds. Archived rows are omitted; disabled rows can be displayed but are not editable. Use capabilities as a current UI hint and handle a later policy/state rejection.

{
  "sub":"cccccccc-cccc-4ccc-8ccc-cccccccccccc",
  "emails":[{
    "id":"dddddddd-dddd-4ddd-8ddd-dddddddddddd",
    "email":"member@example.org","status":"active","verified":true,
    "primary_email":true,"can_send":false,"can_verify":false,
    "can_make_primary":false,"can_remove":false,"resend_after":0
  }]
}
{"bd_carrier":"<carrier>","bd_session":"<session>","bd_key":"<carrier secret>","email_id":"dddddddd-dddd-4ddd-8ddd-dddddddddddd","code":"123456"}

There can be at most ten stored addresses. Add creates pending, unverified, nonprimary email; repeating add for this member's current usable address returns its row. A disabled/archived row is not silently revived. Another unarchived member owning that address in the same organization conflicts; other organizations have separate ownership. Addresses are not account-merging instructions.

Explicit resend issues a ten-minute proof tied to member, address, application, origin, key and initiating selected session. Switching session requires a new send from that context. Resend replaces older proof, including from another carrier. Each challenge permits five attempts; the member has 20 attempts/hour, one send/minute and five sends/hour across apps/carriers. Failed delivery attempts also count. Successful proof consumes the challenge. Resend/verify on an already verified active row returns the current view without another proof consumption. After a lost response reload the list; if still unverified, resend rather than assume success. The first verified address becomes primary when no verified primary exists.

Only verified active email can become primary. Switch primary before removing it; the final verified address is protected. Pending nonprimary addresses may be removed. Choosing primary and removing email affect subsequent me, recovery and email sign-in immediately. Missing/ambiguous primary state is not resolved by arbitrary selection, and email login requires unique current verified ownership. Password recovery can use another verified address as documented in recovery.

Self-service email edits, including removing a verified nonprimary address, keep sessions. Manager removal has a different credential-revocation effect; see manager security. No dedicated universal self-service audit ledger is exposed by these responses.

Error Handling
email_unavailable (409) Address conflict; select another address, never infer the other owner
email_limit, email_not_verified, email_primary, email_last_verified (409) Resolve the ten-address, verification, primary or final-verified protection, then reload
invalid_request (400/404) Malformed ID/code/address or unavailable row
email_code_invalid (400) Wrong/expired code; reload/resend
email_verification_required (409) Expired, exhausted or wrong-session challenge; request a new code within the member budget
email_rate_limited (429) Respect member cooldown and send window
access_denied (403) Organization-managed or inactive address; no self-service edit
session_changed (409) Reload after changed selected authority or address
temporarily_unavailable (503) Concurrent update; retry later with a fresh proof
insufficient_scope (403) Obtain a session with registered email scope
Operational/delivery failure Do not mark verified; reload and follow resend cooldown

Operators need working existing Post/email delivery, protected encrypted transaction storage, and the existing email-confirmation slot secret (at least 32 bytes). These secrets stay server-side. A successful send request does not prove mailbox delivery; setup and live delivery acceptance are separate checks.