# 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](https://m7.org/docs/api/sso.user.m7.org/browser-direct-identities).

## 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](https://m7.org/docs/api/api.user.m7.org/org.md). A valid token
or an OAuth scope alone does not grant Management membership.

Apply [API authorization](https://m7.org/docs/api/api.user.m7.org/authorization.md): 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` |

```http
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.

```json
{
  "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.

## Provider identity unlink

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](https://m7.org/docs/api/api.user.m7.org/tenant-policy.md); for member enrollment and proof behavior see
[tenant two-factor](https://m7.org/docs/api/sso.user.m7.org/tenant-two-factor).

## Related organization contracts

The [organization authority matrix](https://m7.org/docs/api/api.user.m7.org/org.md#organization-roles) 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](https://m7.org/docs/api/api.user.m7.org/org.md#leave-an-organization);
that removes Management access without deleting the tenant account or global
consumer account. See [installation order](https://m7.org/docs/api/api.user.m7.org/organization-upgrade.md).
