Ecosystem

OpenApe Grants

Human-in-the-loop permissions for agents.

OpenApe Grants

@openape/grants

The permission engine. Framework-agnostic.

Grant Lifecycle

Request β†’ Pending β†’ Approved/Denied β†’ (if approved) Active β†’ Used/Expired/Revoked

Grant Types

TypeBehavior
onceSingle use β€” consumed after first use
timedValid for a time window (TTL)
alwaysStanding permission β€” active until revoked

AuthZ-JWT

On approval, a signed AuthZ-JWT is issued:

{
  "sub": "agent@example.com",
  "aud": "target-system",
  "grant_type": "once",
  "permissions": ["deploy"],
  "cmd_hash": "sha256:a1b2c3...",
  "decided_by": "alice@example.com",
  "exp": 1234567890,
  "jti": "unique-grant-id"
}

Key security features:

  • aud binding β€” token only valid for the intended target
  • cmd_hash β€” binds to exact command (prevents substitution attacks)
  • decided_by β€” dual accountability (agent owner β‰  approver)
  • jti β€” replay protection
  • Expiry β€” all grants have a maximum lifetime

Grant Routes in @openape/nuxt-auth-idp

Grant management is integrated into @openape/nuxt-auth-idp. Enable grant pages with grants.enablePages: true in your module config.

@openape/nuxt-grants is deprecated. All grant functionality has been consolidated into @openape/nuxt-auth-idp.

Auto-registered routes (via nuxt-auth-idp):

  • /api/grants β€” list and create grant requests
  • /api/grants/:id β€” get grant details
  • /api/grants/:id/approve β€” approve a grant
  • /api/grants/:id/deny β€” deny a grant
  • /api/grants/:id/revoke β€” revoke an active grant
  • /api/grants/:id/token β€” issue AuthZ-JWT for approved grant
  • /api/grants/verify β€” verify an AuthZ-JWT
  • /api/agent/enroll β€” register a new agent
  • /api/agent/challenge β€” request auth challenge
  • /api/agent/authenticate β€” authenticate with signed challenge

Pages (overridable, enabled via grants.enablePages: true):

  • /grants β€” grant dashboard
  • /grant-approval β€” approve/deny UI
  • /enroll β€” agent enrollment form

openape-escapes (escapes)

A Rust binary for local privilege elevation via the grant system. Supports multiple agents per machine with user-owned keys.

# Install
cargo build --release
sudo make install  # installs to /usr/local/bin/escapes with setuid

# Enroll an agent (key is generated if it doesn't exist)
sudo escapes enroll \
  --server https://id.example.com \
  --agent-email deploy@example.com \
  --agent-name web-deploy \
  --key /etc/openape/agent.key

# Use (--grant identifies the authorization)
escapes --grant <jwt> --reason "Security update" -- apt-get upgrade

Security Model

  • Setuid binary β€” starts as root, drops privileges before loading the user's key
  • User-owned keys β€” private keys belong to the user, stored in user-accessible paths
  • Agent matching β€” public key derived from private key is matched against registered agents in config
  • Privileges re-elevated only after valid AuthZ-JWT with matching cmd_hash
  • Environment sanitized β€” LD_PRELOAD, PATH etc. reset before exec
  • Audit log β€” every execution logged as JSONL