AegisFlow — Policy-Enforced Consent for Autonomous AI Agents
Inspiration
AI agents today can take destructive actions without asking the user again.
Delete repos. Modify systems. Create resources — all with permanent credentials, zero per-action consent.
AegisFlow fixes this with one rule:
One action → one approval → one scoped token.
The agent never holds credentials. Every consequential action requires explicit user consent before Auth0 Token Vault releases the credential. Every decision is permanently audited.
I've watched this problem get solved the wrong way repeatedly. Developers add disclaimers. They add confirmation dialogs. They add logging. None of these stop the agent from acting. They just document that it did.
AegisFlow was built on a different premise: the agent should never hold credentials in the first place. It should earn access to them, one action at a time, with the user's explicit cryptographic approval. Auth0 Token Vault made this possible. This hackathon gave me the deadline to build it.
What it does
AegisFlow is a policy-enforced consent layer for autonomous AI agents. It sits between a user's natural language command and any real-world action, enforcing explicit approval before anything consequential executes.
The execution flow
- User types a plain English command — "Delete the repository Sarvesh5273/test-repo"
- The LLM (Groq, llama-3.3-70b) parses it into a structured
ActionPlanwith a typedaction_type - AegisFlow's Policy Engine classifies the risk — LOW, MEDIUM, or HIGH
- If LOW risk: executes immediately via Auth0 Token Vault, zero friction
- If MEDIUM/HIGH risk: agent halts. A consent card appears showing exactly what will happen
- User approves via Auth0 step-up authentication — explicit consent requesting
execute:high_riskscope - AegisFlow calls the Auth0 Management API (M2M) to retrieve the GitHub token from Token Vault
- Real GitHub API is called. Action executes.
- Consent record + action log + GitHub operation written to the SQLite audit trail
The agent never sees the user's GitHub credentials. Ever. Auth0 Token Vault holds them. The agent earns access one approved action at a time.
One action → one approval → one scoped token.
Security model
- Agent holds zero standing credentials — only a short-lived Auth0 JWT
- Every protected endpoint requires RS256 JWT verification
- Scope enforcement:
execute:high_riskchecked server-side, not client-side - Blocked actions are logged same as successful ones — full audit either way
Supported actions
| Action | Risk Level | Consent |
|---|---|---|
| Read repositories | LOW | Auto-approved |
| Create issue | MEDIUM | Step-up auth |
| Create repository | MEDIUM | Step-up auth |
| Delete repository | HIGH | Step-up auth + irreversibility warning |
Four UI tabs
- ** Agent Console** — chat-style interface, risk cards, formatted execution results
- ** Audit Log** — action history, consent records, GitHub operations — all timestamped
- ** Policy Registry** — runtime-editable policies, change risk levels live without restarting
- ** Token Vault** — shows active vault connections, confirms token presence, and displays available integrations (Slack, Google, Linear) using the same policy engine and vault pattern
How we built it
The system is intentionally split into layers:
- LLM → parses intent into structured actions. Never touches security logic.
- Policy Engine → enforces risk classification and consent requirements
- Token Vault → retrieves credentials only at execution time. Agent never holds them.
- Audit layer → records every action, approval, and vault access atomically
The LLM never makes security decisions.
Backend (FastAPI + Python)
llm.py — Groq API via instructor forces structured JSON output conforming to a Pydantic ActionPlan model. The LLM's only job is parsing intent. It never touches security logic.
main.py — Policy Engine evaluates every action against the registered policy registry. The run_policy_check() function is the single source of truth for what requires consent.
security.py — Verifies Auth0 JWTs using RS256 public key verification via PyJWKClient with JWKS caching. No valid token means no execution.
token_vault.py — Calls the Auth0 Management API using M2M credentials to retrieve the user's stored GitHub OAuth token. The agent process never receives or stores the credential directly.
github_executor.py — Four async GitHub API executors using the vault token. Every executor writes results to SQLite.
database.py — SQLite with three tables: action_logs, consent_records, github_state. Every execution writes to all three.
Auth0 Configuration
- Custom tenant:
aegisflow.us.auth0.com - GitHub social connection with "Authentication and Connected Accounts for Token Vault" purpose
- Custom API (
https://api.aegisflow.local) withexecute:high_riskscope - M2M application with
read:usersandread:user_idp_tokensscopes on Management API - SPA authorized to request
execute:high_riskfrom users
Frontend (React + Vite)
- Chat-style Agent Console with live risk classification
- Repos as cards, issues show live URL, deletions show confirmation — never raw JSON
- Low-risk actions auto-execute silently. Medium/high halt and show consent cards.
- Policy Registry editable at runtime via
PUT /policies/update— no restart needed
Challenges we ran into
Key finding for Auth0 developers:
read:user_idp_tokensmust be granted separately fromread:userson the M2M application or the vault token is silently stripped from the identities response. No error is thrown. This is the single most impactful undocumented behavior in the Token Vault Python integration.
1. The silent Token Vault failure
The Auth0 Management API returns the user identity object with the access_token field silently stripped when read:user_idp_tokens scope is missing — no error, no warning, just an empty field. The documentation explains the concept clearly but doesn't surface this scope requirement in the Python setup flow. Two hours of debugging a non-error. The fix was one checkbox.
2. Python 3.9 compatibility
The instructor library uses Python 3.10+ union type syntax (str | None) internally. On Python 3.9 this causes a hard startup crash. The fix is eval_type_backport — but this isn't mentioned in the installation guide for Python 3.9 users.
3. LLM action type drift
Without strict system prompt constraints, the LLM invents new action_type values that the Policy Engine doesn't recognize — causing silent policy misses. If the LLM can invent action types, it can potentially bypass policy checks entirely. The fix was an explicit enumeration in the system prompt with a hard instruction to never create new ones.
4. Cached login before Token Vault was enabled
If a user logs in with GitHub before the social connection is configured for Token Vault, Auth0 creates the identity record without storing the access token. Subsequent logins using the cached session don't re-trigger the GitHub OAuth flow. The vault stays empty with no visible error.
Accomplishments that we're proud of
Token Vault is genuinely working end-to-end. The GitHub token lives in Auth0. The agent retrieves it via M2M. The user's credential never touches our server. This is not a mock or simulation — it is the real pattern working in production.
The Policy Engine is runtime-editable. Change a DELETE operation from HIGH to MEDIUM risk through the UI and the next command immediately runs through the new policy. No restart. No redeployment.
The audit trail is complete. Every action has a corresponding consent record, action log entry, and GitHub operation record. A judge can reconstruct exactly what happened, who approved it, what scope was granted, and when.
Zero credentials in the agent. The architecture physically cannot expose GitHub credentials to the agent process. The only credential the frontend ever holds is the short-lived Auth0 JWT.
The UI reflects the security model. Low-risk renders as green cards. Medium-risk shows an orange consent gate. High-risk shows a red irreversibility warning. The visual language matches the risk level — judges see the security story without reading code.
What we learned
One action → one approval → one scoped token. That is the mental model that makes AI agents safe to deploy.
The hardest problem in agentic AI is not capability. It is accountability.
The right mental model for Token Vault: do not think of it as credential storage. Think of it as a trust boundary. The agent is not a trusted principal with standing access. It is a request-making entity that must justify every consequential action to the user in real time, earn a scoped token, use it once, and have that use recorded permanently.
Risk classification should be explicit, auditable, and user-modifiable — not hardcoded by the developer or delegated to the LLM's judgment. The LLM is good at understanding intent. It is not a reliable security boundary. The Policy Engine is.
What's next for AegisFlow
Slack, Google, and Linear executors — the policy engine and vault pattern are provider-agnostic. Each new integration requires one executor file and one policy entry. No changes to the security model.
CIBA (Client-Initiated Backchannel Authentication) — async approval via push notification. Agent initiates, user approves from their phone, agent proceeds or halts. No keyboard required. The pattern that makes always-on agents safe.
Time-bound consent — "approve this token for the next 5 minutes only." Expiring grants the user sets at approval time. Limits blast radius of a compromised session.
Multi-agent support — AegisFlow as a consent broker between orchestrator and sub-agents, each with independently scoped vault access.
Policy-as-Code export — download the policy registry as YAML, commit to source control, enforce across environments.
Revocation dashboard — one-click revocation of vault access per connection, per agent, per time window.
Bonus Blog Post
Building AegisFlow: What Token Vault Actually Taught Me About AI Agent Security
I started this hackathon thinking Token Vault was a credential storage feature. I finished it understanding it is a trust boundary enforcement mechanism — and that distinction matters enormously for how we build AI agents.
The standard mental model for giving an AI agent access to external APIs goes like this: store credentials somewhere secure, inject them at startup, and let the agent use them as needed. This model has a fundamental flaw. The agent holds permanent, unbounded access to everything it has credentials for. If the agent misbehaves, hallucinates a destructive action, or gets compromised, there is no per-action check. There is no user in the loop. There is no audit trail that proves what happened and who approved it.
Token Vault breaks this model at exactly the right place. Instead of giving the agent credentials, you give the agent a short-lived JWT that proves the user logged in and granted specific scopes. When the agent needs to call an external API, it presents the JWT to your backend. Your backend calls the Auth0 Management API using M2M credentials to retrieve the vault token. The external API is called. The agent never holds the credential.
The practical implication is significant. The user's GitHub token never travels through the agent's memory, application logs, or network traffic. It lives in Auth0's encrypted vault and is retrieved only at the moment of execution — only after scope verification, only after the user has explicitly consented via step-up authentication.
Building AegisFlow forced me to think carefully about what "user control" actually means in the context of AI agents. It is not enough to show the user what the agent is about to do. The user needs cryptographic proof that the agent cannot act without their approval. That proof is the scoped JWT — unforgeable, auditable, and time-limited.
The most valuable friction I encountered was the read:user_idp_tokens scope requirement. The documentation explains Token Vault clearly but doesn't surface this specific scope in the Python setup flow. I spent hours debugging a silent failure — the Management API returning the identity object with access_token stripped, no error, no warning. The fix was one checkbox. The discoverability gap is real and worth fixing.
These are not complaints. They are the friction that reveals where documentation needs to grow to match the ambition of the product. Auth0 for AI Agents is solving the right problem. Token Vault is the right primitive. AegisFlow is my attempt to show what using it correctly looks like.
AegisFlow turns AI agents from trusted executors into accountable systems.
The agent does not act. It requests.
The user does not trust. They approve.
Every action is intentional. Every approval is provable.
Log in or sign up for Devpost to join the conversation.