OpenAgentIDDocumentation
Developer guides
OpenAgentIDDeveloper guide

Agent OpenID Connect

A real OIDC provider with signing keys, discovery, JWKS, PKCE and current agent authority.

@openagentid/oidc@0.2.0 uses the maintained oidc-provider implementation to authenticate agents to registered relying parties. Node 20.19+ is required.

npm install @openagentid/oidc@0.2.0

A relying party must register and trust your issuer, client and exact redirect URI. Installing a library does not make an arbitrary RP accept that issuer, nor deploy a LifeID federation registration.

Configure protected keys and durable storage

createAgentOidcProvider(options) is asynchronous. These are real deployment inputs, not automatically supplied defaults:

OptionRequired deployment contract
issuerStable public HTTPS issuer; its discovery and callbacks must use that origin.
clientsRegistered client metadata and exact permitted redirect URIs. Public code clients use token_endpoint_auth_method: 'none'.
jwksProtected private RSA/RS256 or Ed25519/EdDSA JWKs with unique kids. Public JWKS exposes no private material.
cookieKeysExplicit rotating cookie signing keys, each at least 32 bytes.
adapter and persistent: trueDurable shared provider storage with atomic token consumption, expiry and grant revocation.
verifyAgentCryptographic possession, signed chain, current root authority/revocation and atomic proof replay checks.
resolveIdentityCurrent authoritative signed-chain/root/revocation recheck; not a cached prior possession verdict.

RS256 is the usual RP default. An Ed25519-only issuer registers clients with id_token_signed_response_alg: 'EdDSA'. Enable trustProxy only behind a trusted TLS terminator that sanitizes forwarded headers. Test mode requires NODE_ENV=test and a loopback issuer; it is not a production bypass.

The adapter implements the upstream provider storage contract and the AgentGrantIdentity model, preserving arbitrary JSON fields, expiring records, consuming tokens atomically and revoking grants. persistent: true declares your deployment's actual storage custody; it does not create a database.

This typed integration connects already configured custody/storage/client metadata to a real SDK verifier:

import { createAgentOidcProvider, type AgentOidcProviderOptions } from '@openagentid/oidc';
import { IdentityVerifier } from '@openagentid/sdk/identity-verification';

type Deployment = Omit<AgentOidcProviderOptions, 'verifyAgent' | 'resolveIdentity'>;
export async function configureIssuer(deployment: Deployment, verifier: IdentityVerifier) {
  return createAgentOidcProvider({
    ...deployment,
    verifyAgent: (proof, context) => verifier.verify(proof, context),
    resolveIdentity: did => verifier.resolve(did, { audience: deployment.issuer }),
  });
}

The verifier requires an authoritative resolveDelegations for current resolution. See verification for its actual adapters. The package README documents the complete provider configuration and upstream storage adapter link.

Mount oidc.callback() on the Node host. The provider serves discovery at /.well-known/openid-configuration, public keys at /jwks, and /authorize, /token and /userinfo.

The host implements /interaction/:uid:

  1. Call oidc.interaction(req, res) to obtain the registered clientId, requested scopes and an interaction-specific {audience, nonce} challenge.
  2. Obtain explicit agent consent and a possession proof for that exact challenge.
  3. On the same signed-cookie interaction, call oidc.completeInteraction(req, res, {proof, consent: true, lifeIdToken?}).
  4. The RP redeems the authorization code with its registered authentication and S256 PKCE verifier, then validates the signed ID token's issuer, audience, nonce, signature and expiry.

There is no login route accepting an arbitrary accountId. Only identity scopes openid and profile are granted. OIDC login grants no inference, billing or tool capabilities.

Owned identities and LifeID federation

Configure lifeId: {issuer, audience, jwksUri} with the actual registered human federation issuer/client and requireLifeId: true when owner authentication is required. Federation verifies the human JWT signature, exact issuer/audience, expiry and issued-at. The verified subject and organization must match the agent's current proven owner. Conflicting organization aliases are refused.

The owned result includes the actual owner and root.kind: 'lifeid'. LifeID/WorkOS remains human and organization authority; Blinds brokers credentials and Genesis KMS protects customer secrets. Library configuration does not certify that a hosted LifeID registration or end-to-end RP login is live.

Explicit self-rooted identities

Self-rooted login is disabled by default. Set allowSelfRooted: true only with the verifier's authoritative current authorizeSelfRoot policy. Complete the exact interaction with proof and consent, omitting lifeIdToken. The flag, a signature or an unsigned caller root does not create approval.

The result has owner: null and root: {kind: 'self', did, authorizationId, revision}. RPs explicitly decide whether their policy accepts this mode. Owned interactions can still require LifeID on the same provider; self roots never receive a fabricated human owner.

Every login, code redemption and UserInfo call rechecks current identity. Root mode/DID, owner, self authorization ID/revision changes, withdrawal, revocation or expiry invalidate grants. Tokens cannot outlive verified identity. Preserve that binding rather than accepting a stale cached result.

OidcBridge and ACT/JWT exchange helpers remain separate legacy interfaces. They require real identity derivation and broker mint hooks; the old generated 0.1.x examples are not configuration for this provider.

On this page