Skip to main content

Auth & Security

Authentication Overview

Behavry has two separate authentication planes:

PlaneWhoMechanismToken
Agent authAI agents (SDK, simulators)OAuth 2.1 client credentialsRS256 JWT (short-lived)
Admin authHuman operators (dashboard)Password / Clerk OIDC / Generic OIDCRS256 JWT

Both planes use the same RS256 keypair.


Agent Authentication

OAuth 2.1 Client Credentials Flow

  1. Admin registers an agent → receives client_id + client_secret (plaintext, one-time)
  2. Agent calls POST /api/v1/auth/token with client_id and client_secret
  3. Behavry verifies the secret hash (bcrypt), creates a Session, issues a JWT
  4. Agent uses the JWT as Authorization: Bearer <token> on all proxy requests
  5. On every proxy request, Behavry:
    • Validates JWT signature and expiry
    • Checks the session_id (JWT jti) is still active in the database
  6. Sessions can be explicitly revoked — the DB check catches revoked sessions even if the JWT is not yet expired

JWT Payload (Agent Token)

{
"sub": "<agent_id>",
"jti": "<session_id>",
"iss": "behavry",
"exp": 1700000000,
"iat": 1699996400,
"roles": ["filesystem-reader", "db-analyst"],
"permissions": ["filesystem:read", "database:read"],
"risk_tier": "medium"
}

Admin Authentication

Password Provider (default)

  • Username + password submitted to POST /api/v1/auth/admin/login
  • Password verified against bcrypt hash
  • JWT issued; stored in localStorage as behavry_admin_token
  • Dashboard decodes the JWT client-side (no signature verification — display only) to get username

Clerk OIDC

Set BEHAVRY_AUTH_PROVIDER=clerk. Clerk handles the sign-in flow; the backend validates Clerk session tokens using the Clerk SDK.

Dashboard requires VITE_CLERK_PUBLISHABLE_KEY in dashboard/.env. The ClerkTokenSync component keeps the Clerk session token in localStorage so the existing API client needs no changes.

Generic OIDC (Entra ID, Okta, Ping)

Set BEHAVRY_AUTH_PROVIDER=oidc. The backend validates tokens against the configured JWKS endpoint and issuer. Used for enterprise IdP integration.


RBAC

Model

Agent → AgentRole → Role → permissions + resource_scopes

Permissions are strings evaluated by OPA policies. Examples:

PermissionMeaning
filesystem:readRead files via filesystem MCP server
filesystem:writeWrite files (also required for delete-escalation)
database:readQuery database (non-sensitive tables)
database:writeInsert/update records
database:sensitive_readQuery PII/financial tables
slack:readList Slack channels
slack:postPost to non-broadcast, non-protected channels
slack:protected_channelsPost to admin/security channels
github:readList repositories
github:writeCreate issues
github:mergeMerge pull requests
web:readHTTP GET requests
web:writeHTTP POST requests

Resource scopes constrain where permissions apply:

{
"name": "project-reader",
"permissions": ["filesystem:read"],
"resource_scopes": ["/home/projects/"]
}

An agent with this role can only read files under /home/projects/.

Super Admin

AdminUser rows with is_super_admin=true and tenant_id=null are break-glass super-admins. They can see and manage all tenants. Created automatically on first boot as <admin_username>-super.


Session Model

  • Sessions are created at agent login and tracked in the sessions table
  • Every proxy request validates session_id against the DB (active check)
  • Sessions expire after a configurable TTL (not yet exposed as a config var — defaults to token expiry)
  • Revocation: admin can revoke a session via DELETE /api/v1/sessions/{id} (not yet implemented in UI — use API directly)
  • On logout (POST /api/v1/auth/logout), the session is marked revoked

Audit Trail

Every authentication event, policy decision, and tool call is written to audit_events. The audit log:

  • Is append-only (no UPDATE or DELETE on audit rows)
  • Includes an event_hash (SHA-256 of content) and previous_hash forming a tamper-evidence chain
  • Is stored in a TimescaleDB hypertable (partitioned by timestamp)
  • Can be exported to SIEM via webhook (CEF or JSON format)

See Audit & Integrity for the full schema.


DLP (Data Loss Prevention)

The DLP scanner runs on every tool call's input parameters before the OPA call. It detects:

PatternSeverity
AWS/GCP/Azure access keyscritical
Generic API keys / tokenshigh
Private keys (PEM)critical
SSN (US Social Security Number)high
Credit card numbers (Luhn check)high
Email addressesmedium
Phone numberslow

Actions:

  • critical: Block the request immediately (before OPA)
  • warn (anything lower): Log the finding, proceed with OPA evaluation

DLP findings are written to audit_events.dlp_findings (JSONB array).


Agent Security Baseline

An approved baseline enforces:

  1. Tool manifest: any tool call using a tool not in the registered list is blocked as "baseline drift"
  2. System prompt hash: on initialize, if the agent sends a behavry.system_prompt_hash meta-field and it doesn't match the registered hash, a system_prompt_drift alert is raised (non-blocking)

See Domain Model — AgentBaseline.


Threat Considerations

ThreatMitigation
Stolen agent JWTShort expiry; DB session check on every request; explicit revocation
Stolen client_secretBcrypt hash stored; plaintext returned once; token can be rotated
Prompt injection via tool responseBehavioral monitor tracks anomaly in action sequences; alerts raised
System prompt tamperingPrompt hash checked on initialize; drift alert created
Tool manifest driftBaseline enforcement blocks unregistered tools
Policy bypassOPA is fail-closed; unreachability = deny
Sensitive data exfiltrationDLP scanner on all inputs; filesystem blocked paths in OPA
Multi-tenant data leakagetenant_id on all entities; middleware sets context on every request
Escalation abuseEscalations time out automatically; all decisions are audited