Skip to content

Enterprise IAM (Nevis)

Nevis Security Suite OAuth2/OIDC, FIDO2, and role-to-permission mappings for enterprise deployments.

Revka can delegate authentication and authorization to a Nevis Security Suite instance, so agent access is governed by your existing enterprise identity provider rather than by local pairing tokens alone. When Nevis IAM is enabled, Revka validates incoming OAuth2/OIDC tokens, resolves the caller’s identity and roles, enforces MFA, and maps each Nevis role to a precise set of Revka tool permissions and workspace access — all on a deny-by-default basis.

Use this page when you need SSO-backed access control, FIDO2/passkey MFA, and role-based tool gating for a multi-team or multi-tenant Revka deployment. For the local-only auth model, see Secrets, pairing & device auth. For how these checks fit into the broader enforcement stack, see the Security model.

Nevis IAM has two cooperating parts:

  • NevisAuthProvider — validates a bearer token (or session token) against your Nevis instance, resolves a NevisIdentity (user ID, roles, OAuth2 scopes, MFA status, session expiry), and rejects the request if MFA is required but not satisfied, or if the session has expired.
  • IamPolicy — takes the resolved identity and evaluates, per request, whether any of the caller’s Nevis roles grants access to the requested tool and workspace. With no matching role mapping, access is denied.

Both parts log every decision (ALLOW/DENY) to tracing, and the user ID is redacted in logs.

All settings live under the [security.nevis] section. The integration is off until you set enabled = true.

[security.nevis]
enabled = true
instance_url = "https://nevis.corp.example.com"
realm = "production"
client_id = "revka-agent"
client_secret = "enc2:<hex>" # encrypted at rest (see note below)
token_validation = "remote" # local | remote
jwks_url = "https://nevis.corp.example.com/.well-known/jwks.json"
require_mfa = true
session_timeout_secs = 3600
[[security.nevis.role_mapping]]
nevis_role = "agent-operator"
revka_permissions = ["file_read", "file_write", "shell"]
workspace_access = ["production"]
[[security.nevis.role_mapping]]
nevis_role = "agent-admin"
revka_permissions = ["all"]
workspace_access = ["all"]
KeyTypeDefaultMeaning
enabledboolfalseTurn Nevis IAM on. When false, all other keys are ignored.
instance_urlstring""Base URL of your Nevis instance. Required when enabled.
realmstring"master"Nevis realm to authenticate against. Required when enabled.
client_idstring""OAuth2 client ID registered in Nevis. Required when enabled.
client_secretstring(none)OAuth2 client secret. Stored encrypted as enc2:<hex>. Optional for public clients.
token_validationstring"local""local" (JWKS) or "remote" (introspection). See Token validation modes.
jwks_urlstring(none)JWKS endpoint for local validation. Required when token_validation = "local".
require_mfaboolfalseReject any session where MFA was not completed. See MFA enforcement.
session_timeout_secsu643600Session lifetime in seconds. Must be greater than 0.
role_mappingarray[]One [[security.nevis.role_mapping]] block per Nevis role. See Role mappings.

When enabled = true, Revka validates the configuration at load time and fails fast rather than deferring errors to the first request. Startup is rejected if:

  • instance_url, client_id, or realm is empty.
  • token_validation is anything other than "local" or "remote".
  • token_validation = "local" but jwks_url is unset.
  • session_timeout_secs is 0.

token_validation selects how NevisAuthProvider checks an incoming token.

Revka calls the Nevis OAuth2 introspection endpoint for every token. This is always current — if a token is revoked in Nevis, the next request is rejected — at the cost of a network round trip per validation.

POST {instance_url}/auth/realms/{realm}/protocol/openid-connect/token/introspect
Content-Type: application/x-www-form-urlencoded
token=<bearer-token>&client_id=<client_id>&client_secret=<client_secret>

The response must report active: true; Revka then reads sub (user ID), realm_access.roles (roles, sorted and de-duplicated), scope, exp (session expiry), and the MFA signals acr / amr. A missing or empty sub claim, or active: false, is rejected.

[security.nevis]
token_validation = "remote"
# jwks_url not required

Session (cookie-based) tokens are validated separately against the Nevis userinfo endpoint, regardless of token_validation, and the resulting session expires after session_timeout_secs.

Set require_mfa = true to reject any identity that did not complete multi-factor authentication. Revka treats a session as MFA-verified when either:

  • the token’s acr (Authentication Context Class Reference) claim equals "mfa", or
  • the token’s amr (Authentication Methods References) claim contains any of fido2, passkey, otp, or webauthn.

If require_mfa = true and neither signal is present, validation fails with an MFA-required error (the user ID is redacted in the message). FIDO2 and passkey authentications performed in Nevis therefore satisfy Revka’s MFA gate automatically — no separate Revka-side enrollment is needed.

Each [[security.nevis.role_mapping]] block maps one Nevis role to the Revka tools and workspaces it may use.

[[security.nevis.role_mapping]]
nevis_role = "agent-operator"
revka_permissions = ["file_read", "file_write", "shell"]
workspace_access = ["production"]
FieldTypeMeaning
nevis_rolestringNevis role name. Matched case-insensitively (trimmed and lowercased).
revka_permissionslistTool names this role may invoke. ["all"] grants every tool.
workspace_accesslistWorkspaces this role may access. ["all"] grants every workspace. Optional (defaults to none).

How evaluation works:

  • Per-request, two checks. Tool access and workspace access are evaluated independently. Both tool name and workspace name are matched case-insensitively.
  • Union across roles. If a caller holds multiple Nevis roles, their grants are unioned — access is allowed if any held role grants it.
  • "all" is a wildcard. revka_permissions = ["all"] grants every tool; workspace_access = ["all"] grants every workspace.

A worked example using three roles:

[[security.nevis.role_mapping]]
nevis_role = "admin"
revka_permissions = ["all"]
workspace_access = ["all"]
[[security.nevis.role_mapping]]
nevis_role = "operator"
revka_permissions = ["shell", "file_read", "file_write"]
workspace_access = ["production", "staging"]
[[security.nevis.role_mapping]]
nevis_role = "viewer"
revka_permissions = ["file_read"]
workspace_access = ["staging"]

With this config: admin can use any tool in any workspace; operator can run shell in production or staging but is denied browser; viewer can read files in staging but is denied shell and file_write.

The IAM policy denies anything it does not explicitly allow:

  • An unknown role (no matching nevis_role mapping) is denied.
  • An identity with no roles is denied.
  • An empty tool or workspace name is denied.
  • An empty role_mapping list denies everything — even a user whose Nevis role is admin gets no access, because there is no mapping to grant it.

This means enabling Nevis without any role_mapping blocks effectively locks the agent down until you add mappings. Start with the minimum each role needs and widen deliberately.

Role names are normalized (trimmed and lowercased) before being indexed. The IamPolicy builder detects when two mappings collapse to the same normalized key — for example "admin" and " ADMIN " — and returns a duplicate role mapping error rather than silently letting the last one win. Silent last-wins overwrites can accidentally broaden or revoke access. Empty role names (whitespace-only) are skipped, not treated as duplicates.

Independently of Nevis, the gateway can accept FIDO2 hardware tokens and platform authenticators (YubiKey, SoloKey, Touch ID, Windows Hello) via the [security.webauthn] section. This path is compiled in only when Revka is built with the webauthn cargo feature.

Terminal window
cargo build --release --features webauthn

Use this when you want hardware-key gateway authentication without (or alongside) a full Nevis deployment. For the gateway endpoints and registration flow, see TLS, rate limiting, WebAuthn & static serving and Cargo feature flags & ADRs.

  1. Register a client in Nevis. Create an OAuth2/OIDC client (client_id, optional client_secret) and note your instance_url and realm.

  2. Configure [security.nevis]. Set enabled = true, fill in instance_url, realm, client_id, and (for now) token_validation = "remote". Add the client_secret — it is encrypted to enc2:<hex> on save.

  3. Add role mappings. Define one [[security.nevis.role_mapping]] block per Nevis role, with explicit revka_permissions and workspace_access. Remember: no mappings means no access.

  4. Turn on MFA. Set require_mfa = true so FIDO2/passkey/OTP completion in Nevis is required for every authenticated request.

  5. Validate startup. Restart the gateway and confirm it loads cleanly — configuration errors (missing required fields, invalid token_validation) fail fast at startup.

  6. Verify in the audit log. Allow/deny decisions are logged. Cross-check them in the Audit log.