Getting Started

How It Works

The DDISA login flow and grant system explained.

How It Works

Login Flow (DDISA)

User enters email at SP
        ↓
SP extracts domain → DNS lookup: _ddisa.example.com
        ↓
Discovers IdP URL → Redirects to IdP /authorize
        ↓
User authenticates with Passkey (or Agent via Ed25519)
        ↓
IdP issues authorization code → Redirect back to SP
        ↓
SP exchanges code for signed JWT (backchannel)
        ↓
SP validates JWT (issuer, audience, signature, nonce, act)
        ↓
User is logged in ✅

This is a standard Authorization Code + PKCE flow, enhanced with DNS-based IdP discovery and Passkey-only authentication.

Grant Flow (Permissions)

When an agent needs to perform a privileged action:

1. Agent Requests a Grant

POST /api/grants
{
  "requester": "agent@example.com",
  "target": "prod-server",
  "grant_type": "once",
  "permissions": ["deploy"],
  "reason": "Deploy hotfix #123"
}

2. Human Reviews

The agent's owner or designated approver sees the request in the web UI (or via notification) and approves or denies it.

3. Agent Receives AuthZ-JWT

On approval, the agent can request a signed AuthZ-JWT:

{
  "sub": "agent@example.com",
  "act": "agent",
  "aud": "prod-server",
  "grant_type": "once",
  "permissions": ["deploy"],
  "decided_by": "alice@example.com",
  "exp": 1234567890
}

4. Target Verifies

The target system validates the AuthZ-JWT: signature, audience, expiry, permissions, and optionally cmd_hash for exact command binding.

escapes — Privilege Elevation for Agents

escapes is a Rust binary that brings the grant flow to local privilege elevation. It supports multiple agents per machine, each with their own user-owned Ed25519 keypair.

escapes --grant <jwt> -- systemctl restart nginx
  1. Loads config (as root), then drops privileges to real user
  2. Loads private key from configured path (as user), derives public key
  3. Matches public key against registered agents in config
  4. Authenticates to the matched agent's IdP via Ed25519
  5. Creates a grant request (with SHA-256 hash of the command)
  6. Waits for human approval
  7. Receives AuthZ-JWT, verifies cmd_hash matches
  8. Re-elevates to root, sanitizes environment, executes command

The binary runs with the setuid bit — it starts as root, drops privileges before key loading, and only re-elevates after JWT verification.