HelixID
Cryptographic identity and authorization for AI agents. Replace API keys with verifiable, scoped, and auditable agent identity.
HelixID is built on W3C Verifiable Credentials 2.0 and W3C DIDs 1.0, and is Apache-2.0 licensed.
You will sometimes see HelixID described as "Auth0 for AI agents." That is shorthand for the category, not the whole pitch — HelixID is built on open standards, cryptographic verifiability, and decentralized trust. It is a trust primitive, not a SaaS wrapper.
It also does not replace OAuth. Use OAuth for sessions and simple internal APIs. Use HelixID for cross-org trust, delegation chains, and auditable credentials. See Why not just use OAuth?.
The Problem
AI agents are authenticating with static API keys and bearer tokens — credentials designed for humans clicking through OAuth consent screens, not autonomous software making thousands of cross-boundary decisions per hour.
This breaks in predictable ways:
- No delegation chain. When Agent A spawns Agent B to call Service C, there's no standard way to prove B is authorized to act on A's behalf.
- No scoped authority. API keys are all-or-nothing. An agent that needs read access to one table gets the same key as one that needs admin access to everything.
- No cross-org trust. When your agent calls a third-party service, both sides rely on shared secrets and manual API key exchange. There's no way to verify authority without bilateral integration.
- No revocation that works. Revoking a compromised agent means rotating keys across every service it touched.
- No audit trail. "Who authorized this agent to do that?" is answered by grepping logs, not cryptographic proof.
HelixID fixes this by giving every AI agent a cryptographic identity — a portable, verifiable, revocable credential that works across organizational boundaries without requiring the parties to know each other in advance.
How It Works
In one sentence: an agent carries signed credentials proving what it may do, the service it calls verifies them locally before acting, and every decision is recorded.
Two credentials matter, and they come from different parties:
- Agent-Authority VC — issued once by the HelixID issuer when the agent is onboarded. This is the agent's ceiling: the most it could ever be allowed to do.
- Delegated Grant VC — issued by the service provider after the user logs in and consents. This is what the user actually approved, for that one service.
Authority is the intersection of the two. A grant can never widen what the issuer gave the agent, and the agent can never act beyond what the user approved. HelixID holds the agent's key in custody and signs on its behalf, so the agent never handles key material itself.
This two-party split is the part most often flattened into a single issuer by mistake. It is covered in full in The Two-Issuer Model.
The whole trust chain in one pass — two issuers, a local signature, in-process verification, and an audit record either way.
Open the full-size version.Walking the diagram:
| Step | What happens |
|---|---|
| 1–2 | The agent asks HelixID for a Verifiable Presentation (VP). The API bundles the credentials and signs with the agent's server-held key. |
| 3 | The agent makes its normal tool call, with the signed VP attached. |
| 4 | The service verifies signature, expiry, revocation, and scopes in-process — it never calls the issuer to ask whether this particular request is allowed. |
| 5 | Allowed → the tool runs. Denied → an error, and the action never happens. |
| 6 | The outcome is written to the audit log either way — approvals and refusals. |
Step 4 is what makes this usable on a hot path and across organizations that have no prior integration with each other. It's also the claim most worth stating precisely — see What "Offline Verification" Actually Means.
What HelixID Does
HelixID is a 5-layer trust stack for AI agents, not just an identity library:
| Layer | What It Does | How |
|---|---|---|
| 1. Identity | Every agent gets a DID (Decentralized Identifier) bound to a cryptographic keypair | W3C DID (did:web default, did:key local, did:hedera optional) |
| 2. Authority | Scoped, time-bound credentials that prove what an agent is allowed to do | W3C Verifiable Credentials with delegation chains |
| 3. Enforcement | Runtime verification and authorization checks at execution boundaries | SDK/core verification + verifier-owned policy checks |
| 4. Audit | Ordered record of the whole chain — issuance, consent, presentation, verification, authorization, action, result | Adapter-based audit_log store + structured stdout/file |
| 5. Revocation | Decentralized revocation read as a static, cacheable document — no per-credential call to the issuer | Bitstring Status List |
Each layer is covered in Core Concepts.
Roles
HelixID is built around three distinct actors. Each has a different relationship with the SDK and the issuer service.
| Role | Who | What they do |
|---|---|---|
| Platform Operator | The team building the AI product | Creates issuer DID, mints bootstrap tokens, issues VCs to agents, manages revocation |
| AI Agent | The autonomous software process | Requests VPs from HelixID, presents credentials, delegates authority to sub-agents |
| Service Provider | The API or service the agent calls | Verifies incoming VPs, checks scopes, optionally issues a session JWT or caches the result |
Platform Operator
The operator runs the issuer service (self-hosted helix-api or CLI for low volume). It holds agent keys in custody and signs on their behalf, so the operator controls both issuance policy and the credential that authorizes signing — see Security model.
// Operator: mint a bootstrap token for a new agent (authenticated operator call)
// POST /v1/enrollment-tokens
// { agentName, requestedScopes, maxDelegationDepth, requestedDomains }
// → { bootstrapToken }
// Operator: revoke an agent's credential
// CLI
helix revoke --vc-id <vcId> --status-list ./public/status/1.json --wallet issuer.enc
The operator's private key (issuer signing key) never leaves the issuer service. It is the trust anchor for every VC issued in their trust domain.
AI Agent
The agent has no wallet and no private key of its own — the API holds the only copy, generated when the agent was onboarded, and signs on the agent's behalf.
- TypeScript
- Python
import { HelixClient, verifyVP } from '@helixid/sdk-js'
const client = new HelixClient('http://localhost:3000', {
adminApiKey: 'dev-admin-key-change-in-production',
})
// the server signs on the agent's behalf -- it holds the only copy of the key
const vp = await client.signVP(agentDid, 'orders-service')
const result = await verifyVP(vp, client, { expectedTargetService: 'orders-service' })
console.log(result.valid, result.agentDid, result.privilegeScopes)
// delegate to a sub-agent — also an API call, same trust boundary as signVP
const childVC = await client.delegateAuthority(agentDid, 'did:key:z6Mk...sub-agent', ['read:orders'], 3600)
from helix_sdk import HelixClient, verify_vp
client = HelixClient(
"http://localhost:3000",
admin_api_key="dev-admin-key-change-in-production",
)
# the server signs on the agent's behalf -- it holds the only copy of the key
vp = client.sign_vp(agent_did, "orders-service")
result = verify_vp(vp, client, expected_target_service="orders-service")
print(result["valid"], result["agentDid"], result["privilegeScopes"])
# delegate to a sub-agent — also an API call, same trust boundary as sign_vp
child_vc = client.delegate_authority(agent_did, "did:key:z6Mk...sub-agent", ["read:orders"], 3600)
Service Provider
verifyVP() is an API call to helix-api's POST /v1/vp/verify — signature check, delegation-chain walk, expiry, target service, and revocation all happen server-side, with VP_VERIFIED/VP_REJECTED audit logging handled there too. The only thing the verifier does locally is enforce the result and manage its own session/cache.
- TypeScript
- Python
import { verifyVP, SessionManager, HelixClient } from '@helixid/sdk-js'
const client = new HelixClient(process.env.HELIX_API_URL!)
const result = await verifyVP(incomingVP, client, {
expectedTargetService: 'orders-service',
})
// replay protection — verifier owns this store; the VP's own expiry bounds the TTL
const ttl = Math.floor((new Date(incomingVP.expirationDate).getTime() - Date.now()) / 1000)
const seen = await redis.get(`vpid:${result.vpId}`)
if (seen) throw new Error('REPLAY_DETECTED')
await redis.set(`vpid:${result.vpId}`, '1', 'EX', ttl)
// scope check — effectiveScopes is the enforcement field: identical to
// privilegeScopes unless the VP carried a consent grant, in which case it is
// the intersection of the two
if (!result.effectiveScopes.includes('read:orders')) throw new Error('INSUFFICIENT_SCOPE')
// session handling — verifier's choice, both optional
// Option A: issue a short-lived JWT, agent reuses it for subsequent calls
const session = new SessionManager({ secret: process.env.JWT_SECRET!, ttl: 600 })
const token = await session.issue({ agentDid: result.agentDid, scopes: result.effectiveScopes })
// Option B: cache the VP result by vpId, skip re-verification on repeat calls
await cache.set(`vp:${result.vpId}`, result, { ttl })
import os
from datetime import datetime, timezone
from helix_sdk import verify_vp, SessionManager, HelixClient
client = HelixClient(os.environ["HELIX_API_URL"])
result = verify_vp(incoming_vp, client, expected_target_service="orders-service")
# replay protection — verifier owns this store; the VP's own expiry bounds the TTL
expires_at = datetime.fromisoformat(incoming_vp["expirationDate"].replace("Z", "+00:00"))
ttl = int((expires_at - datetime.now(timezone.utc)).total_seconds())
seen = redis.get(f"vpid:{result['vpId']}")
if seen:
raise Exception("REPLAY_DETECTED")
redis.set(f"vpid:{result['vpId']}", "1", ex=ttl)
# scope check — effectiveScopes is the enforcement field: identical to
# privilegeScopes unless the VP carried a consent grant, in which case it is
# the intersection of the two
if "read:orders" not in result["effectiveScopes"]:
raise Exception("INSUFFICIENT_SCOPE")
# session handling — verifier's choice, both optional
# Option A: issue a short-lived JWT, agent reuses it for subsequent calls
session = SessionManager(secret=os.environ["JWT_SECRET"], ttl=600)
token = session.issue(result["agentDid"], result["effectiveScopes"])
# Option B: cache the VP result by vpId, skip re-verification on repeat calls
cache.set(f"vp:{result['vpId']}", result, ttl)
Neither session option is required. The verifier can re-verify the VP on every call if preferred. The SDK supports all three paths.
Standards & Ecosystem Alignment
HelixID builds on established and converging standards:
- W3C Verifiable Credentials 2.0 (Recommendation, May 2025) — credential format
- W3C Decentralized Identifiers 1.0 (Recommendation) — identity layer
- W3C StatusList2021 — decentralized revocation
- W3C AI Agent Protocol Community Group (est. June 2025) — cross-origin agent communication
- DIF Trusted AI Agents Working Group — industry alignment
- NIST NCCoE — AI Agent Identity and Authorization (concept paper, Feb 2026)
Next Steps
- Quick Start — three ways in, all running locally
- The 5-Layer Trust Stack — the concepts, in order
- SDK Reference — every public surface
HelixID is built by DgVerse — building the trust layer for digital credentials and AI agents.