- The Problem
- The Solution
- Key Features
- Tech Stack
- Architecture
- Getting Started
- Demo Scenarios
- Policy Configuration
- Token Vault Integration
- Patterns for Agent Authorization
- License
A zero-trust authorization layer for AI agents using Auth0 Token Vault, CIBA, and a YAML policy engine. Every tool call is evaluated against security policies, authenticated through Token Vault, and logged as an auditable consent receipt.
Built for the Authorized to Act: Auth0 for AI Agents hackathon.
AI agents are increasingly given access to third-party APIs (GitHub, Slack, etc.) on behalf of users. But most implementations store raw OAuth tokens in application memory, give agents blanket permissions, and provide no audit trail of what the agent actually did. This creates a significant security and trust gap.
Agent Firewall enforces zero-trust authorization for every agent action:
- Policy Engine evaluates each tool call against YAML-defined rules
- Auth0 Token Vault manages all third-party tokens securely via Connected Accounts
- CIBA (Client-Initiated Backchannel Authentication) requires real-time user approval for high-risk actions
- Consent Receipts create an auditable log of every action with user ID, risk level, policy rule, and result
| Risk Level | Auth Method | Example Actions |
|---|---|---|
| Low | Token Vault (auto-approve) | List repos, list channels |
| Medium | Token Vault (auto-approve) | Create issues |
| High | CIBA (user approval required) | Send Slack messages |
| Critical | Always denied | Delete repositories |
- Token Vault Only -- Auth0 manages the full OAuth token lifecycle; the app never sees refresh tokens. Tokens are retrieved via
getAccessTokenForConnection()with no fallback. - Policy-as-Code -- YAML rules with wildcard pattern matching and default-deny for unknown actions
- Step-Up Authorization (CIBA-inspired) -- High-risk actions require explicit user approval on the Approvals page before execution proceeds via Token Vault
- Connected Accounts -- Users connect GitHub/Slack through Auth0's Connected Accounts flow, which stores tokens in Token Vault
- Consent Receipts -- Every action logged with user ID, risk level, timestamps, policy rule, and results
- Security Dashboard -- Live stats (approved/denied/pending), activity feed, and receipt explorer with JSON export
-
Framework: Next.js 16 (App Router, Turbopack)
-
AI: Vercel AI SDK v6 + OpenAI GPT-4o
-
Auth: Auth0 for AI Agents (
@auth0/ai-vercel,@auth0/nextjs-auth0v4) -
UI: Tailwind CSS v4 + shadcn/ui
-
Providers: GitHub (repos, issues) + Slack (channels, messages)
User Browser
|
v
+--------------------------------------------------+
| Next.js API (POST /api/chat) |
| |
| 1. Policy Engine (YAML rules) |
| tool call -> pattern match -> risk level |
| -> auth method (token_vault / ciba / deny) |
| |
| 2. Auth0 Token Vault |
| auth0.getAccessTokenForConnection() |
| -> short-lived GitHub/Slack access token |
| |
| 3. CIBA-Inspired Step-Up (High-Risk Only) |
| User approves on Approvals page |
| |
| 4. Consent Receipt Store |
| userId, toolName, risk, status, result |
+--------------------------------------------------+
| |
v v
GitHub API Slack API
For a visual overview of the request/authorization flow, see:
High-level:
- Node.js 18+
- Auth0 account (free trial works)
- OpenAI API key
- GitHub App configured in Auth0 with Token Vault enabled
- Slack App configured in Auth0 (Sign in with Slack connection)
- Create a Regular Web Application in Auth0 Dashboard
- Under Authentication > Social, configure GitHub connection:
- Use a GitHub App (not OAuth App) with "Expire user authorization tokens" enabled
- Set Purpose to "Authentication and Connected Accounts for Token Vault"
- Enable the My Account API under Applications > APIs
- Add a client grant for your app to the My Account API with scopes:
create:me:connected_accounts,read:me:connected_accounts,delete:me:connected_accounts - Under Authentication > Social, configure Slack connection:
- Create a Slack App with scopes:
channels:read,chat:write,channels:history,users:read - Set Purpose to "Authentication and Connected Accounts for Token Vault"
- Create a Slack App with scopes:
- Enable the Token Exchange grant type (
urn:auth0:params:oauth:grant-type:token-exchange:federated-connection-access-token) on your application
# Clone the repository
git clone https://github.com/prabhakaran-jm/agent-firewall-auth0.git
cd agent-firewall-auth0
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env.local
# Edit .env.local with your Auth0 and OpenAI credentials
# Run the development server
npm run devOpen http://localhost:3000 to see the login page.
| Variable | Description |
|---|---|
AUTH0_SECRET |
Random 32-byte secret for session encryption |
AUTH0_BASE_URL |
App URL (e.g., http://localhost:3000) |
AUTH0_ISSUER_BASE_URL |
Auth0 tenant URL |
AUTH0_CLIENT_ID |
Web app client ID |
AUTH0_CLIENT_SECRET |
Web app client secret |
AUTH0_DOMAIN |
Auth0 tenant domain (e.g., your-tenant.us.auth0.com) |
AUTH0_CUSTOM_API_CLIENT_ID |
Custom API client ID (for Token Vault exchange) |
AUTH0_CUSTOM_API_CLIENT_SECRET |
Custom API client secret |
AUTH0_AUDIENCE |
API identifier (e.g., https://agent-firewall-api) |
OPENAI_API_KEY |
OpenAI API key |
- Sign in via Auth0 (GitHub login)
- Go to Accounts page and click Connect on GitHub
- Authorize the GitHub App -- this stores your token in Auth0 Token Vault
- Go to Chat and try: "List my GitHub repos"
- Check Receipts to see the audit trail
"List my GitHub repos"
The agent calls list_repos, evaluated as Low risk. Token Vault provides a short-lived GitHub access token via getAccessTokenForConnection(). Auto-approved; consent receipt logged.
"Create an issue on agent-firewall-auth0 titled Bug Report"
The agent calls create_issue, evaluated as Medium risk. Same Token Vault flow. Auto-approved; consent receipt logged with issue details.
"Delete my repo called test-project"
The agent calls delete_repo, which matches the Critical risk deny rule. Immediately BLOCKED by the firewall. Denial receipt logged. The agent explains why it was blocked.
"Send a message to #general saying hello"
The agent calls send_message, which triggers the CIBA-inspired step-up approval flow. The agent pauses and creates a pending approval request. The user must navigate to the Approvals page and explicitly approve before the message is sent via a fresh Token Vault token.
Policies are defined in policies/default.yaml:
rules:
- name: "GitHub read operations"
provider: github
actions: [list_repos, list_issues]
risk: low
auth: token_vault
- name: "GitHub write operations"
provider: github
actions: [create_issue]
risk: medium
auth: token_vault
- name: "Deny delete operations"
provider: "*"
actions: [delete_repo, delete_issue]
risk: critical
auth: deny
- name: "Slack send message"
provider: slack
actions: [send_message]
risk: high
auth: ciba
default:
risk: critical
auth: denyAny action not matching a rule is denied by default (zero-trust).
All GitHub tools use Auth0 Token Vault exclusively -- no Management API fallback:
async function getGitHubTokenFromVault(): Promise<string> {
const result = await auth0.getAccessTokenForConnection({
connection: "github",
});
return result.token;
}The Connected Accounts flow ensures Auth0 stores the GitHub refresh token securely. The app only ever receives short-lived access tokens (ghu_* format) through the token exchange grant. Raw refresh tokens never leave Auth0.
- Policy-as-Code with Default Deny -- Define rules in YAML, evaluate at runtime, deny everything else
- Token Vault as Single Source -- All third-party tokens managed by Auth0, zero fallbacks
- Risk-Based Auth Escalation -- Low risk = auto-approve, High risk = CIBA, Critical = deny
- Consent Receipts as Audit Trail -- Every action produces a structured, queryable receipt
- Safe Execute Wrapper -- Catch tool errors and return them as results (don't crash the stream)
- Real User Identity -- Use Auth0
subclaims for all receipt logging
MIT
