Organization member security administration

User M7 exposes Organization → Clients → member → Security, with email, linked-identity, two-factor and recent-audit views. These controls operate on the selected tenant member, separately from the member Properties save. Every mutation requires a reason; removal, unlink and reset additionally ask for explicit confirmation in the UI. New provider linking remains member self-service.

Authority and HTTP contract

The owning service is API User. Use POST JSON under https://api.user.m7.org/api/v2/org/client with a human consumer access token whose principal has current active membership with role owner or admin in the organization's Management group. Machine and tenant-member credentials are rejected on these eight routes. This is narrower than general organization management. A valid token or an OAuth scope alone does not grant Management membership.

Apply API authorization: accepted resource audience and current token/session/principal, Bearer for an unbound token, DPoP plus ath for a bound token, and the original fingerprint where required. Route scopes below apply to scoped third-party clients under the existing dot-prefix policy; the first-party requester/target scope exemption does not waive manager checks. The API checks the live stored role at request entry and under the administration transaction's grant lock, including after remote email proof work. A member or legacy viewer role is denied. Do not grant access based on a UI role label.

Every request requires org (organization UUID) and id (member UUID). Only the additional fields listed below are accepted. No caller-provided actor/principal selector is accepted. Every mutation also requires nonempty trimmed reason, at most 500 bytes, without control characters. Do not place credentials or sensitive verification material in an audit reason.

Relative POST path Required OAuth scope Additional fields beyond org,id
/security/status org.client.security.read None
/emails/add org.client.emails.manage reason,email
/emails/resend org.client.emails.manage reason,email_id
/emails/verify org.client.emails.manage reason,email_id,code
/emails/primary org.client.emails.manage reason,email_id
/emails/remove org.client.emails.manage reason,email_id
/identities/unlink org.client.identities.unlink reason,identity_id
/two-factor/reset org.client.two_factor.reset reason,authenticator_id
POST /api/v2/org/client/emails/add HTTP/1.1
Host: api.user.m7.org
Authorization: Bearer <unbound manager access token>
Content-Type: application/json

{"org":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa","id":"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb","email":"member@example.org","reason":"Member requested an additional recovery address."}

Use valid runtime IDs and the correct credential transport. A disabled member can be managed; an archived member is read-only. Current org, Management group, membership link, actor, target and relevant ownership are rechecked under lock, including before/after remote email work. Losing authority during a dialog invalidates the action. Browser-side capability flags are not authorization.

Status and response projections

Success uses the standard envelope {"status":1,"comment":"OK","data":...}. Status data contains org, id, permissions, emails, identities, two_factor, and audit.

Projection Public fields
permissions email_manage, identity_unlink, two_factor_reset, identity_link: false
Email rows id,email,status,verified,primary_email,can_send,can_verify,can_make_primary,can_remove,resend_after
Identity rows id,provider,handle,verified,linked_at,last_login,can_unlink; no remote provider subject or credentials
two_factor available,email_available,pending,enrolled,enabled,authenticator_id,name,verified_at,email_logins,email_enabled
Audit rows id,occurred_at,event,principal_id,outcome,reason,target_id,sessions_revoked

Mutation data returns the refreshed panel with audit_id, integer sessions_revoked and boolean revocation_pending; add also returns email_id. The manager status reports retained enrollment and the saved email preference even while current org policy makes factor use unavailable. No TOTP seed, backup-code plaintext/hash, challenge binding, email confirmation code/job ID, provider token, raw provider subject, session secret or root token is exposed.

{
  "status":1,"comment":"OK",
  "data":{
    "org":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
    "id":"bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
    "permissions":{"email_manage":true,"identity_unlink":true,"two_factor_reset":true,"identity_link":false},
    "emails":[],"identities":[],
    "two_factor":{"available":false,"email_available":false,"pending":false,"enrolled":false,"enabled":false,"authenticator_id":null,"name":null,"verified_at":null,"email_logins":false,"email_enabled":false},
    "audit":[]
  }
}

This example illustrates a status response, not a mutation result. Failures use API User's unsuccessful response and diagnostic comment, not SSO's stable OAuth error vocabulary. Handle token/proof HTTP failures through the shared authorization guide and operation failures through the API envelope. Never parse comment prose as a stable code or convert an error into an empty successful panel. Reload status after a conflict or uncertain result.

Email ownership workflow

Add accepts a valid address up to 254 bytes, trimmed/lowercased. It creates only a pending unverified nonprimary row and does not send email. At most ten stored addresses are permitted. A duplicate on this member is an error (unlike the self-service add receipt); another unarchived member's ownership in this org also conflicts. Other organizations have independent ownership. Disabled or archived email is not silently revived.

Choose Resend explicitly, then Verify with email_id UUID and six-digit string code. The ten-minute challenge is tied to org, member, address and initiating manager. Another manager must request a new code. Manager limits span the member across manager attempts: five attempts per challenge, twenty/hour, one send/minute and five/hour. New sends replace old proof and failed delivery attempts count. Sending mail is not ownership verification. Changing the address, authority or current ownership invalidates the operation. No database transaction is kept open across mail delivery. Self-service email confirmation has a separate proof/budget store; the two surfaces share ownership locks, not interchangeable verification challenges or a combined quota.

Only verified active addresses can be primary. The first verified address becomes primary if needed. Switch primary before removing it; the last verified address is protected. Pending/unverified nonprimary addresses may be removed. Add, resend, verify and primary keep sessions. Removing verified email closes this member's email-authenticated and legacy unattributed tenant sessions across apps and hosted SSO; unverified removal closes none. Self-service email removal keeps sessions and is a different authority contract.

After a lost add/verify/remove response, reload status before repeating. Repeated mail send consumes budgets; repeated proof is not general idempotency. If still unverified after an uncertain consumption, request a new proof. Throttling and primary/last-address/ownership conflicts must remain visible to the manager.

Review the local identity_id, supply a reason and explicitly confirm removal. The manager acts through Management authority, not a claimed provider proof for the target member. An identity cannot be moved between members. New links require the member's explicit provider authentication and confirmation.

At least one usable sign-in method must remain: another verified provider, native delegated password identity or consumer link. Email alone does not satisfy the manager unlink safeguard. Member self-service has its own retained email-proof rules. Unlink closes sessions attributed to that identity and legacy unattributed sessions across this member's hosted and browser-direct apps; known sessions from other methods remain. Reload after lost response; the reviewed local ID must not be replaced by a newly discovered ID in an automatic retry.

Two-factor reset

Submit the exact authenticator_id displayed in the reviewed panel. When no linked factor exists, an explicit empty string permits clearing pending setup; omission is not the same request. A replacement factor makes the old ID stale and reset must fail, requiring a new review. No member TOTP is needed for an authorized manager reset. Org allowances being off do not prevent clearing a retained factor.

Reset clears linked/pending enrollment, backup codes, saved preferences and outstanding challenges. It immediately closes all this member's local hosted tenant and browser-direct sessions across apps, including brokered sessions. That revocation scope does not make brokered login require local tenant 2FA. Password/provider/email credentials remain. There is no forced-enrollment mode: subsequent admitted sign-in can proceed without a factor until a new enrollment.

Audit and revocation completion

Successful local mutations, audit recording and local session closure commit together; audit failure rolls them back. Mail requests also record requested events, which are not proof of delivery or completed verification. Recent audit shows up to 30 tenant.member.admin.* events ordered newest first (event ID breaks ties), without a public pagination contract. It is a recent operational view, not an immutable or permanent audit archive.

Action Local tenant session closure
Add/send/verify/primary email; remove unverified email None
Remove verified email Email-authenticated plus legacy unattributed, all apps and hosted SSO
Unlink provider That identity plus legacy unattributed, all apps and hosted SSO
Reset 2FA All member sessions in hosted tenant SSO and browser-direct apps

Remote Identity family revocation follows local commit, attempts at most eight roots per request, and can remain revocation_pending for the existing API reconciliation process. A returned local count is not a remote success count. Do not hide a completed local change merely because cleanup is pending, or claim remote completion from a timeout. Other members, consumer sessions, independent Device Code grants and API keys are outside this local session selection. The service does not promise instant deletion of application cookies or every offline-validated token. A revoked browser learns on its next authenticated request/renewal; applications must handle that rejection.

For retained-factor availability and exact organization switches see tenant policy; for member enrollment and proof behavior see tenant two-factor.

The organization authority matrix distinguishes owner org controls from owner/admin tenant administration. Management scope tags and membership pub do not bypass these security checks. A human admin/member may separately leave their own organization; that removes Management access without deleting the tenant account or global consumer account. See installation order.