> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Org security posture operations: sessions, 2FA enforcement, support access, and PII redaction

> Run the four operational workflows behind Settings → Security: review and revoke sign-in sessions, roll out org-wide per-role 2FA, grant time-boxed support access, and choose your PII redaction posture.

# Org security posture operations

**Settings → Security** renders seven cards. Four of them are operational workflows you run as part of keeping the org's posture where you want it: session review and revocation, org-wide 2FA enforcement, support-access granting, and PII redaction. This guide walks each one, with the API calls behind it and the audit row each action writes.

The other three cards (org IP allowlist, SAML SSO, SCIM provisioning) plus your own operator 2FA are covered in the [security console guide](https://docs.orbit.devotel.io/guides/settings-security-console.md); the per-API-key IP allowlist is a separate, programmatic control covered in its [own guide](https://docs.orbit.devotel.io/guides/api-key-ip-allowlist.md).

Every control on this page is **tenant-owned and default-off**. Orbit does not mandate session policies, 2FA enrollment, support access, or redaction for any organization; you choose what to enforce, for which roles, and when. The concepts behind this layer (step-up challenges, backup codes, the per-role policy model) are on the [account security model](https://docs.orbit.devotel.io/concepts/account-security-model.md) page.

## Scope map

| Card | What it gates | Covered by |
| - | - | - |
| Two-factor authentication | A TOTP second factor and backup codes for **your own** operator login | [Security console guide](https://docs.orbit.devotel.io/guides/settings-security-console.md) |
| Require 2FA | Whether members of each role must enroll a second factor before the dashboard lets them in | This guide |
| Session management | Visibility and revocation of the org's active sign-in sessions | This guide |
| Support access | Whether Devotel support can sign in as your workspace, and for how long | This guide |
| PII redaction | On-screen masking of contact details and write-time scrubbing of agent transcripts | This guide |
| SSO (SAML) | Identity-provider login for the whole org | [Security console guide](https://docs.orbit.devotel.io/guides/settings-security-console.md) |
| IP allowlist | Which source IPs can open the dashboard | [Security console guide](https://docs.orbit.devotel.io/guides/settings-security-console.md) |

Two boundaries worth keeping straight before you operate:

* The org IP allowlist gates **session (dashboard) traffic only**. Programmatic requests authenticate per API key, and each key carries its own `allowed_ips` list; see the [per-API-key IP allowlist guide](https://docs.orbit.devotel.io/guides/api-key-ip-allowlist.md).
* The require-2FA policy and the operator 2FA card are different levers: the card enrolls *your* factor, the policy decides *which roles* must have one.

## Session review and revocation

Two reads give you the full picture of who is signed in:

* `GET /api/v1/settings/sessions` — the devices **currently signed in** as a member: browser/device label, source IP, approximate location, and last-active time. This is what the **Active Sessions** card renders.
* `GET /api/v1/settings/login-history` — the merged **sign-in history**: active, ended, expired, and revoked sessions (most recent 30), enriched with IP, user-agent, and location from the audit log. This is what the **Login History** card renders, and it is the surface for spotting a session that already ended oddly.

Both endpoints return an empty list rather than an error when the identity provider is unreachable, so an empty card is never silently mistaken for "no sessions"; refresh from the card if a load fails.

### Spot an unrecognized device

1. Open **Settings → Security** and read the Active Sessions card top to bottom. The current session is flagged **This device** and sorted first; every other row is a session someone holds against your org.
2. Compare each row's device label, IP, location, and last-active time against what the member says they use. A phone-shaped session for a member who has no phone enrolled, an IP from a country nobody works in, or a last-active time after the device was reported lost is the classic unrecognized row.
3. If the label is bare (the sign-in provider reported no browser or device details), the card explains why rather than leaving an unlabeled row; fall back to the login-history read, which adds user-agent and location enrichment from the audit log.

### Revoke it

Use the row's **Revoke** action, or call the endpoint directly:

```bash theme={null}
curl -X DELETE "https://api.orbit.devotel.io/api/v1/settings/sessions/{sessionId}" \
  -H "Authorization: Bearer $SESSION_JWT"
```

The `{sessionId}` value comes from each row's `id` on `GET /api/v1/settings/sessions`.

* The revocation takes effect org-wide: the session ends everywhere it is held, so the member is signed out on every tab and device using it, not just the one you were looking at.
* The revoked member's next request fails authentication and lands them on sign-in; in the login-history read the row moves to revoked status. There is no grace window and no undo.
* The action writes a `session.revoked` audit row with the acting operator and source IP.
* The current session cannot be revoked from this surface; sign out through the normal flow instead. This is deliberate, so a reviewer can never accidentally revoke the session they are working from.

When you suspect broad unauthorized access, **Revoke all other sessions** on the Active Sessions card signs out everything except the session you are holding, in one confirmed action. Follow a panic revocation with the require-2FA rollout below so the next sign-in needs a factor the attacker does not have.

## Org-wide 2FA enforcement

The **Require 2FA** card (owner-only write) sets a per-role policy over `GET`/`POST /api/v1/settings/security/require-2fa`. The policy is a bitmap over the five roles — `owner`, `admin`, `developer`, `viewer`, `billing` — and each role flips independently. A role whose bit is set cannot use the dashboard until every member holding it enrolls a second factor; unset roles stay not-required. The read returns the full map, so you can always round-trip what is currently enforced.

Writes merge a partial bitmap, so you toggle one role without re-sending the whole map:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/settings/security/require-2fa" \
  -H "Authorization: Bearer $SESSION_JWT" \
  -H "Content-Type: application/json" \
  -d '{ "admin": true, "developer": true }'
```

### Staged rollout order

1. **Announce.** Tell the team what is coming and give a date; enrollment takes a minute per person but stragglers are locked out at the deadline, not before.
2. **Admins and developers first.** These roles hold the most mutating surface and their members are quickest to enroll without help.
3. **Viewers and billing next.** Watch for lockout noise before you widen further; a viewer who only reads reports may need a nudge and a backup-code printout.
4. **Owner last.** Enroll your own factor first, then set `owner: true`.

### The self-lockout guard

`POST` rejects a write that sets `owner: true` while your own account has no enrolled second factor, with a `422` explaining why. The policy can therefore never strand the person enforcing it; enroll on the operator 2FA card first, then flip the bit.

### What a blocked member sees

A member of a required role who has no factor signs in to an enrollment redirect: the `/me` response carries the redirect, the dashboard routes them straight to TOTP enrollment, and they cannot reach anything else until enrollment completes. Expect a short tail of these the morning after each rollout step.

Every bitmap change writes a `security.require_2fa.updated` audit row with the per-role before→after diff and the actor, so a SOC 2-style reviewer can reconstruct the rollout from the audit log alone. The policy is default-off and tenant-owned; Orbit never sets it for you.

## Support access SOP

Devotel support can sign in as your workspace **only** inside a window you grant, from the **Support access** card. Grants and denies are owner-only; admins see the card read-only so they can watch status and active sessions without holding the lever.

### Grant a bounded window

Pick the shortest window that covers the support case and press **Grant access**, or call it directly:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/settings/security/support-access/grant" \
  -H "Authorization: Bearer $SESSION_JWT" \
  -H "Content-Type: application/json" \
  -d '{ "minutes": 60 }'
```

The dashboard offers 15-minute to 24-hour presets; 30 minutes is the default. The grant expires on its own at the end of the window; nothing to remember, nothing left open.

While a window is live, **Active support sessions** lists each support sign-in with its reason, start, and expiry, and **End session** on a row (or `POST /api/v1/settings/security/support-access/sessions/{jti}/end`) signs that session out without closing the window.

### Deny and revoke semantics

**Deny access** (`POST /api/v1/settings/security/support-access/deny`) closes the window **and ends every active support session immediately**. Use it two ways:

* **Routine close-out.** The support case resolved before the window ran out; deny rather than leaving an open door into the weekend.
* **Leak signal.** Treat any of these as "deny now, investigate after": an active support session you did not grant, a grant with no open support case, or a session that outlives the case it was opened for. Denying ends the access in one action, and the deny itself is a durable record that someone closed the door.

### What the audit log records

| Event | Audit action |
| - | - |
| Window granted | `security.support_access.granted` |
| Window denied (sessions ended) | `security.support_access.denied` |
| One active session ended by your org | `security.support_access.session_ended_by_tenant` |
| Support sign-in accepted inside a window | `auth.impersonation_consumed` |
| Sign-in attempt rejected after revocation | `auth.impersonation_exchange_rejected` (reason `session_revoked`) |

The last two rows come from the support side of the same flow; a rejected attempt is not an attack by itself (it means revocation worked), but `auth.impersonation_consumed` rows you cannot match to a grant you made are exactly the leak signal above. The failure-path codes a support engineer sees (`SESSION_REVOKED`, `TOKEN_ALREADY_USED`, …) and their meanings are in the [support access troubleshooting page](https://docs.orbit.devotel.io/troubleshooting/support-access-impersonation.md).

## PII redaction posture

The **Privacy** card carries two independent redaction controls; they protect different surfaces and you can run either, both, or neither.

| Control | When it applies | What it affects | What it does NOT affect |
| - | - | - | - |
| Display redaction (`pii_redaction_enabled`) | Read time, on screen | Masks phone numbers and email addresses on-screen for viewer-tier operators | Dial targets and outbound payloads, which always carry the raw values |
| Transcript redaction (`pii_redaction_in_transcripts`) | Write time, before storage | Scrubs PII out of agent conversation turns as they are written to transcript storage | Anything already stored |

Choose by what you are worried about:

* **Display-only** is a viewing control: a viewer-tier operator sees masked contact details while routing work, but the system still dials and sends the real values. Turning it on changes what people see, never what Orbit sends.
* **Write-time** is a data control for orgs whose posture says transcripts must not retain PII at all: new agent conversation turns are scrubbed before they land in storage.

> [!WARNING]
>
> Write-time redaction is irreversible and not retroactive. Turns written while the control is off keep their original content forever; enabling the control only scrubs new turns from that moment on. If retention (not just redaction) is part of your posture, pair it with the transcript retention window on the same card, which purges conversations older than the set number of days nightly (blank means keep forever).

The three fields on the card save together through `PUT /api/v1/settings/privacy`, always sending the full current state so a single toggle can never silently unset a neighbour, and the write lands as a `settings.privacy.updated` audit row. As with everything on this page, both controls default off and are yours to set; because write-time redaction cannot be back-applied, trial it in a non-production org before flipping it on for real.

## Evidence queries

Filter **Settings → Audit log** (or the audit export) by these action names to reconstruct who changed the org's posture and when; see the [audit log guide](https://docs.orbit.devotel.io/guides/audit-log.md) for filtering and export.

| Change | Audit action |
| - | - |
| Session revoked (single row or all-others) | `session.revoked` |
| Require-2FA bitmap changed | `security.require_2fa.updated` |
| Operator 2FA disabled / backup codes regenerated | `security.2fa.disabled` / `security.2fa.backup_codes_regenerated` |
| Support window granted / denied | `security.support_access.granted` / `security.support_access.denied` |
| Active support session ended by your org | `security.support_access.session_ended_by_tenant` |
| Support sign-in consumed / rejected | `auth.impersonation_consumed` / `auth.impersonation_exchange_rejected` |
| PII redaction or transcript retention changed | `settings.privacy.updated` |

Each row answers the two questions an auditor always asks: who changed it, and from where.

## See also

* [Authentication](https://docs.orbit.devotel.io/authentication.md) — sign-in flows and the session model these controls operate on
* [Account security model](https://docs.orbit.devotel.io/concepts/account-security-model.md) — the concept page for step-up challenges, backup codes, and the per-role policy
* [Security console guide](https://docs.orbit.devotel.io/guides/settings-security-console.md) — org IP allowlist, SAML SSO, SCIM, and operator 2FA
* [Per-API-key IP allowlist](https://docs.orbit.devotel.io/guides/api-key-ip-allowlist.md) — the programmatic sibling of the org allowlist
* [Re-authentication challenge flow](https://docs.orbit.devotel.io/troubleshooting/reauth-challenge-flow.md) — troubleshooting step-up challenges
* [Support access troubleshooting](https://docs.orbit.devotel.io/troubleshooting/support-access-impersonation.md) — failure codes on the support side of a granted window


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.