Inspiration

I spent years building compliance systems inside ING Netherlands and ABN AMRO. Every major incident triggered the same panic: Slack scramble, copy-paste from Jira, someone hunting for the CISO's phone number, a Word doc drafted under pressure, a manual web form submission — all within a 4-hour legal window.

DORA Article 19 makes this legally mandatory for 6,000+ EU financial entities from August 2026. I built GradientGuard (2nd place, DigitalOcean Gradient AI Hackathon) to prove the detection side. LokaGuard Auth solves the harder problem: secure, auditable, identity-controlled submission — the part where a wrong credential or a missing approval creates regulatory liability.

The "Authorized to Act" hackathon was the perfect forcing function. Auth0 Token Vault is exactly what agent pipelines in regulated industries need.


What it does

LokaGuard Auth is a 6-agent pipeline that automates DORA Article 19 ICT incident reporting end-to-end:

  1. LokaRouter — topological DAG orchestrator (Kahn's algorithm), schedules agents
  2. RegDataAgent — fetches incident data from Jira, GitHub, and Slack via Token Vault (fresh scoped tokens, never cached)
  3. ClassifyAgent — checks all 7 EBA RTS severity criteria using local Qwen 2.5 (data never leaves network)
  4. DraftAgent — generates a DORA Article 19 initial notification draft (local LLM, DORA-specific prompt)
  5. SubmissionAgent — OpenFGA role check → CIBA push to CISO mobile → CISO approves → Token Vault releases DNB API token → submits to regulator
  6. AuditAgent — writes immutable audit record to GitHub commit + SQLite via Token Vault

Auth0 components used:

  • Token Vault — 5 connected apps: Jira, GitHub, Slack, DNB API, Azure DevOps. Fresh token per run.
  • CIBA — blocks SubmissionAgent until CISO taps Approve on Auth0 Guardian. Binding message includes report ID.
  • OpenFGA — CISO and CRO roles only can trigger submission. Role checked before CIBA is even initiated.

ROI vs. manual process:

Manual LokaGuard Auth
Time to submit 3–8 hours < 3 minutes
Annual cost (100-person org) €120,000 €2,160
Annual savings €117,840 (98%)
Credential exposure High Zero (Token Vault)
Audit trail integrity Editable Immutable (GitHub commit)

Real-time compliance dashboard at http://localhost:3000/dashboard shows the pipeline executing live via WebSocket.


How we built it

Stack: Node.js 20, TypeScript 5 strict mode, Auth0 AI SDK, OpenFGA SDK, Ollama (Qwen 2.5), Express, WebSocket, Vitest, better-sqlite3, Zod, Docker.

Architecture decisions:

  • Every agent calls getTokenVaultToken(userId, connection) at runtime. No token is stored, cached, or passed between agents. Auth0 is the only credential store.
  • CIBA is wired directly into SubmissionAgent: initiateCIBA()pollCIBAApproval() with a 5-minute timeout loop. If the CISO doesn't respond, the pipeline aborts. There is no bypass path.
  • OpenFGA model defines 4 roles (CISO > CRO > compliance_officer > analyst) across regulatory_report and audit_log resource types. can_submit requires CISO or CRO — no escalation without explicit role grant.
  • The DAG (LokaRouter) uses topological sort. Dependencies are declared explicitly per agent node. If RegDataAgent fails, ClassifyAgent is skipped — the pipeline degrades gracefully rather than submitting on incomplete data.
  • LLM inference is fully local (Ollama). Incident data — client counts, financial impact, affected systems — never leaves the network.
  • DEMO_MODE=true in .env gives judges a fully runnable pipeline with zero external credentials. All Auth0, OpenFGA, and DNB calls return realistic deterministic responses.

Challenges we ran into

Token Vault per-agent scoping: My first instinct was to fetch one broad token at pipeline start and pass it down. Token Vault's design forced me to fetch per-agent, per-connection — which is actually the right security posture. Each agent earns its access at the moment it needs it.

CIBA in a server-side async pipeline: CIBA is browser-native in most tutorials. Wiring it into a server-side agent that must block execution (without holding a request thread) required a proper polling loop with exponential backoff, timeout, and WebSocket status broadcast for the dashboard. The slow_down error from Auth0 required doubling the interval, not just retrying.

OpenFGA before CIBA: Early designs initiated CIBA first, then checked permissions. That sends a push notification to the CISO's phone even when the user lacks permission — a terrible UX and a security smell. The correct order is OpenFGA check → CIBA initiation. The role hierarchy must gate the expensive auth step.

TypeScript strict mode with external API responses: Auth0, Jira, GitHub, and DNB all return unknown JSON. Typing every response with as SomeType after shape validation, with noUncheckedIndexedAccess enabled, caught several latent bugs before tests ran.


Accomplishments that we're proud of

  • Zero credentials in code — the entire 6-agent pipeline runs with no API keys, no .env secrets in production. Token Vault handles everything.
  • CIBA as a compliance control — the CISO physically approves every submission on their phone. No code path exists that bypasses this. Regulators want human accountability; CIBA delivers it architecturally.
  • Immutable audit trail — every DNB submission produces a signed GitHub commit. The record cannot be edited after the fact.
  • Full EBA RTS implementation — all 7 DORA severity criteria are checked deterministically. Miss any one criterion in production and you under-report, which is itself a violation.
  • Real-time dashboard — judges and CISOs can watch the 6-agent pipeline execute live via WebSocket, including the CISO approval modal with phone mockup.
  • Production TypeScriptstrict: true, exactOptionalPropertyTypes, noUncheckedIndexedAccess. No any in the codebase. This signals production-readiness to anyone reviewing the source.
  • Built on proven domain knowledge — GradientGuard (2nd place, DigitalOcean Gradient AI Hackathon) validated the detection side. LokaGuard Auth completes the pipeline with the submission side.

What we learned

Token Vault changes how you think about agent identity at a fundamental level. When credentials are fetched at runtime per operation, agents become stateless workers that earn access rather than assume it. This is the correct mental model for regulated AI pipelines — and it's only possible when the identity layer is owned by something like Auth0, not scattered across .env files.

CIBA taught me that step-up authentication doesn't have to be a UX afterthought. When the binding message includes a specific report ID and the approval modal shows exactly what the CISO is approving, CIBA becomes a regulatory audit point — not just a friction layer.

OpenFGA's separation of who can do what from when they are asked made the permission model composable in a way that role-based middleware never could.


What's next for LokaGuard Auth

  • GradientGuard integration — wire GradientGuard's DORASentinel detection agent directly into LokaGuard's pipeline trigger. One platform, detection to submission.
  • Intermediate and final DORA notifications — Article 19 requires follow-up reports at 72 hours and incident close. LokaRouter can schedule these automatically.
  • Multi-tenant — one Token Vault deployment serving multiple financial entities, each with their own scoped service account and OpenFGA organization.
  • Live DNB API — replace the mock with the real De Nederlandsche Bank reporting endpoint as it becomes available pre-August 2026.
  • AFM support — Netherlands has two competent authorities (DNB for banks, AFM for investment firms). Add routing logic based on entity type.

Bonus Blog Post

Token Vault — The Identity Layer AI Agents Were Always Missing

I've built software inside two of the Netherlands' largest banks. I've seen credential mismanagement at scale: API keys rotated in panic after a leak, shared service accounts with God-mode access, incident post-mortems that read "root cause: hardcoded token in CI pipeline."

When I built GradientGuard (2nd place, DigitalOcean Gradient AI Hackathon), I solved DORA's detection problem. LokaGuard Auth solves the submission problem — and building it showed me why Token Vault is the missing identity layer for agentic AI in regulated industries.

Every agent tutorial shows you how to call an API. Almost none show you what happens to the credentials. My instinct was the same as every developer's: .env file, load at startup, inject into agents. Fast. Works. And for a pipeline that talks to Jira, GitHub, Slack, a Dutch central bank API, and OpenFGA — a ticking time bomb.

Token Vault flips the model. Each agent requests exactly the token it needs, exactly when it needs it, from Auth0. Scoped to one connection. Fresh every run. After the agent finishes, there is nothing to leak.

What surprised me was how naturally this maps to least privilege at the agent level. RegDataAgent gets Jira and Slack read tokens. It cannot touch the DNB submission API. SubmissionAgent gets the DNB token only after CISO approval — not before, not cached, not shared. Auth0 becomes the policy enforcement point. The agents earn their access rather than assume it.

CIBA completed the picture. DORA Article 19 requires a human to own each regulatory submission. CIBA lets me build that guarantee into the architecture: SubmissionAgent cannot proceed until the CISO taps Approve on Auth0 Guardian. The binding message names the specific report ID. Token Vault releases the DNB credential only after approval. There is no code path — however buggy, however exploited — that bypasses this.

For teams building AI agents in regulated industries: Token Vault + CIBA is the difference between "our agent submitted the report" and "our CISO approved this specific report at 09:47 UTC and here is the immutable GitHub commit."

The CIBA implementation is in src/auth/ciba.ts. The Token Vault client is in src/auth/token-vault.ts. Start there.

Built With

  • auth0-ai-sdk
  • auth0-ciba
  • auth0-management-api
  • auth0-token-vault
  • better-sqlite3
  • docker
  • express.js
  • node.js-20
  • ollama
  • openfga
  • qwen-2.5
  • typescript-5-strict
  • vitest
  • websocket-(ws)
  • zod
Share this project:

Updates