End-to-End Tutorial
End-to-End Tutorial
This tutorial walks through setting up a complete OpenApe environment on your local machine: an Identity Provider (IdP), a Service Provider (SP) app, and an AI agent that requests grants.
What We'll Build
┌──────────────────┐ DDISA ┌──────────────────┐
│ Service Provider│◄──────────────►│ Identity Provider│
│ (Nuxt App) │ Login Flow │ (Nuxt + IdP) │
│ localhost:3001 │ │ localhost:3000 │
└──────────────────┘ └──────────────────┘
▲
│ Grant Request
│ + Approval
┌────────┴─────────┐
│ AI Agent (CLI) │
│ grapes + escapes │
└──────────────────┘
By the end, you'll have:
- An IdP that issues Passkey-based logins and manages grants
- An SP app that authenticates users via DDISA
- An enrolled agent that can request and use grants
Part 1: Set Up the IdP
Create the IdP project
npx nuxi@latest init my-idp
cd my-idp
npm install @openape/nuxt-auth-idp
Configure the IdP
Add the module to nuxt.config.ts:
export default defineNuxtConfig({
modules: ['@openape/nuxt-auth-idp'],
openapeIdp: {
rpName: 'My OpenApe IdP',
rpID: 'localhost',
rpOrigin: 'http://localhost:3000',
managementToken: 'dev-management-token-change-in-prod',
grants: {
enablePages: true
}
}
})
Start the IdP
npm run dev -- --port 3000
Verify it's running:
# JWKS endpoint
curl http://localhost:3000/.well-known/jwks.json
# OIDC discovery
curl http://localhost:3000/.well-known/openid-configuration
Part 2: Set Up the SP
In a separate terminal:
Create the SP project
npx nuxi@latest init my-sp
cd my-sp
npm install @openape/nuxt-auth-sp
Configure the SP
export default defineNuxtConfig({
modules: ['@openape/nuxt-auth-sp'],
openapeSp: {
fallbackIdpUrl: 'http://localhost:3000'
}
})
Add a Login Page
Create app/pages/index.vue:
<template>
<div style="max-width: 400px; margin: 50px auto;">
<h1>My App</h1>
<div v-if="user">
<p>Logged in as: <strong>{{ user.email }}</strong></p>
<p>Type: {{ user.act }}</p>
<button @click="logout()">Logout</button>
</div>
<OpenApeAuth v-else />
</div>
</template>
<script setup>
const { user, logout } = useOpenApeAuth()
</script>
Start the SP
npm run dev -- --port 3001
Part 3: Install the CLI and Register a Human User
npm install -g @openape/grapes
Register and Login
grapes login --idp http://localhost:3000
This opens a browser where you register with a Passkey and log in.
localhost, Passkeys use the device's built-in authenticator. On macOS, this uses Touch ID or iCloud Keychain.Verify:
grapes whoami
# → alice@localhost (human) via http://localhost:3000
Part 4: Human Logs In to the SP
- Open
http://localhost:3001in your browser - Enter
alice@localhostin the login form - Since there's no DNS record for
localhost, the SP uses the fallback IdP (http://localhost:3000) - Authenticate with your Passkey
- You're redirected back to the SP, logged in as
alice@localhost
This is the complete DDISA flow: email → IdP discovery → Passkey auth → JWT → SP session.
Part 5: Enroll an Agent
Generate the agent's key and enroll
# Generate a key pair for the agent
ssh-keygen -t ed25519 -f /tmp/agent_key -N ""
# Enroll via the admin API (this still requires curl — it's an admin operation)
curl -X POST http://localhost:3000/api/agent/enroll \
-H "Authorization: Bearer dev-management-token-change-in-prod" \
-H "Content-Type: application/json" \
-d "{
\"email\": \"agent+worker@localhost\",
\"name\": \"test-worker\",
\"publicKey\": \"$(cat /tmp/agent_key.pub)\"
}"
Login as the agent
grapes login --idp http://localhost:3000 --key /tmp/agent_key --email agent+worker@localhost
grapes whoami
# → agent+worker@localhost (agent) via http://localhost:3000
Part 6: Agent Requests a Grant
The agent requests permission to perform an action:
grapes request "echo Hello from OpenApe!" --audience escapes --reason "Testing the grant flow" --wait &
The --wait flag blocks until a human approves or denies. Check the IdP's grant dashboard at http://localhost:3000/grants — you'll see the pending request.
Part 7: Approve the Grant
In a separate terminal, login as the human approver and approve:
grapes login --idp http://localhost:3000
# See pending grants
grapes list --status pending
# Approve
grapes approve <grant-id>
The agent's grapes request --wait in the other terminal now completes — the grant is approved.
Use the grant with escapes
# Get the AuthZ-JWT
JWT=$(grapes token <grant-id>)
# Execute the approved command
escapes --grant "$JWT" -- echo Hello from OpenApe!
Or use grapes run for the one-liner version:
grapes run escapes "echo Hello from OpenApe!" --reason "Testing"
# → Requests grant, waits for approval, executes via escapes
What's Next?
- Agent Integration Guide — Detailed API reference for each endpoint
- OpenApe Grants — Grant types, AuthZ-JWT, and security model
- escapes — Local privilege elevation with grants
- Deployment — Deploy IdP and SP to production