Skip to main content

COG-10: Venue Authentication & Access Control

Status: Draft (Work in Progress)
Version: 0.1
Created: 2026-01-29
Authors: Mike Anderson

:::caution Work in Progress This specification is under active development. Structure and details may change significantly based on implementation experience and community feedback. :::

:::note Related specifications This document specifies how a venue implements authentication and access control — the caller classes, the middleware verification order, venue-signed tokens, and OAuth provider configuration. For the underlying catalogue of mechanisms (including the full Ed25519 self-issued JWT specification, which is not repeated here), see COG-3: Authentication Mechanisms. For capability-based authorisation, see COG-13: Agent Capabilities. :::

This standard specifies the authentication and access control mechanisms for Covia Grid venues. It defines how callers identify themselves, how venues verify identity, and how access control decisions are made.

Purpose

Venues on the Covia Grid expose API endpoints that accept requests from users, agents, and other venues. Authentication determines who is making a request; access control determines whether that request is permitted.

The Covia authentication model supports three classes of caller:

  • Anonymous: No identity presented. Permitted when public access is enabled.
  • Self-identified: The caller presents a self-issued JWT proving control of a cryptographic key pair. No external authority is needed.
  • Authority-backed: The caller presents a JWT issued by the venue (after OAuth login) or by a trusted external provider.

Terminology

See COG-1: Architecture for definitions of Grid terminology. Additional terms used in this specification:

  • Bearer JWT: A JWT presented in the Authorization: Bearer <token> HTTP header (distinct from the opaque bearer tokens / API keys of COG-3 §2)
  • Caller DID: The Decentralised Identifier associated with the authenticated caller
  • Venue Key: The Ed25519 key pair owned by the venue, used for signing venue-issued JWTs
  • JWKS: JSON Web Key Set, a standard format for publishing public keys used to verify JWTs

Specification

Authentication Flow

All API requests (/api/*), A2A requests (/a2a), and MCP requests (/mcp) pass through the authentication middleware. The middleware extracts caller identity from the Authorization header.

Request arrives

├── No Authorization header
│ ├── Public access enabled → Allow (anonymous)
│ └── Public access disabled → 401 Authentication required

└── Authorization: Bearer <token>

├── Try self-issued EdDSA verification
│ └── Success → Caller DID = sub claim (did:key or venue-managed named DID)

├── Try venue-signed EdDSA verification
│ └── Success → Caller DID = sub claim (venue user DID)

├── Try external provider RS256 verification
│ └── Success → Caller identity = email or sub claim

└── All verification paths fail
├── Public access enabled → Allow (anonymous)
└── Public access disabled → 401 Invalid or expired token

The middleware attempts verification in order: self-issued, venue-signed, then external provider. The first successful verification determines the caller identity.

Every accepted token yields the caller identity from its sub claim. What distinguishes the classes is whose authority the token rests on — expressed by the signing key together with a per-class constraint on iss, which keeps the classes disjoint:

ClassAuthority (iss)Caller (sub)Signature key
Self-issuedThe subject itself — iss, when present, MUST equal subdid:key, or a venue-managed named DIDThe kid key, which MUST be authorised for sub (COG-3 §5)
Venue-signedThis venue — iss MUST equal the venue's DIDVenue-scoped user DIDThe venue's own key
External providerThe provider — iss MUST match the configured issuerProvider-scoped subjectA provider JWKS key matching kid

A venue-signed token is an attestation by the venue about its user, so iss ≠ sub is expected there. A self-issued token rests on the subject's own authority, so a token naming any other issuer MUST NOT be accepted as self-issued.

Token Types

Self-Issued EdDSA JWT

A client with an Ed25519 key pair MAY create a self-issued JWT to authenticate. This is the primary authentication method for agents and automated clients.

The full token specification lives in COG-3 §5 and is not repeated here. In summary:

  • The JWT MUST use the EdDSA algorithm
  • The kid header identifies the signing key — canonically its bare Multikey string; the did:key:<multikey> and <sub>#<multikey> forms are also accepted
  • The sub claim is the caller's DID: a did:key whose embedded key equals the kid key, or a venue-managed named-user DID for which the kid key is an active registered authentication key
  • The iss claim, when present, MUST equal sub; it is REQUIRED for venue-managed subjects
  • The JWT MUST include iat and exp; aud is RECOMMENDED and enforced per the venue's audience policy
  • The venue verifies the signature with the kid key, then confirms that key is authorised for sub

Example claims:

{
"iss": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"sub": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"aud": "did:web:venue.example.com",
"iat": 1706500000,
"exp": 1706500300
}

For did:key subjects this mechanism requires no prior registration or shared secrets — any entity with an Ed25519 key pair can authenticate to any venue. A venue-managed subject can authenticate only at its home venue, using a key registered for it there.

Venue-Signed EdDSA JWT

After a successful OAuth login, the venue issues a JWT signed with its own Ed25519 key pair. This binds the OAuth identity to a venue-scoped user DID.

Requirements:

  • The JWT MUST use the EdDSA algorithm
  • The JWT MUST be signed with the venue's key pair
  • The sub claim MUST contain the user's venue-scoped DID (e.g. did:web:venue.example.com:u:alice_gmail_com)
  • The iss claim MUST contain the venue's DID
  • The iat and exp claims MUST be present
  • Expiry is controlled by the venue's auth.tokenExpiry configuration (default: 86400 seconds / 24 hours)

Example claims:

{
"sub": "did:web:venue.example.com:u:alice_gmail_com",
"iss": "did:web:venue.example.com",
"iat": 1706500000,
"exp": 1706586400
}

The venue verifies these tokens using its own public key. No external key material is needed.

External Provider RS256 JWT

Clients that already hold a valid ID token from a configured OAuth provider MAY present it directly as a bearer token. The venue verifies it against the provider's JWKS endpoint.

Requirements:

  • The JWT MUST use the RS256 algorithm
  • The JWT kid header MUST match a key in the provider's JWKS endpoint
  • The JWT MUST pass claim validation (issuer, audience, expiry)
  • The venue extracts the email claim (preferred) or sub claim as the caller identity

Verification process:

  1. Parse the JWT and check the algorithm is RS256
  2. Extract the kid from the header
  3. For each configured OAuth provider with a JWKS endpoint: a. Fetch the provider's JWKS and find the key matching kid b. Verify the RS256 signature c. Validate claims: issuer matches provider, audience matches clientId, token not expired
  4. If verification succeeds, extract the caller identity from email or sub

Anonymous Access

When auth.public.enabled is true (the default), requests without a valid bearer token are allowed through without a caller identity. The caller DID is null for anonymous requests.

Anonymous access is suitable for:

  • Development and testing
  • Public read-only APIs
  • Venues that implement their own access control at the application layer

When auth.public.enabled is false, all requests MUST include a valid bearer token. Requests without a token or with an invalid token receive a 401 response.

Public Capability Ceiling

Anonymous requests do not run unconstrained: the venue assigns the anonymous caller class a capability scope — the public capability ceiling — evaluated by the ordinary capability machinery (COG-13). The ceiling is configured with auth.public.caps:

auth.public.capsEffect
(absent — the default)A secure read-only profile: crud/read scoped to the venue's public identity (<venueDID>:public) plus unscoped asset/read. No invoke, agent, or mutating ability is granted, so every mutating operation — including operation invocation — is denied to anonymous callers.
"unrestricted"No ceiling — anonymous callers are unscoped (the legacy permissive behaviour).
An explicit capability arrayExactly that scope.

A malformed value MUST fail closed to the default read-only profile. The ceiling applies only to anonymous callers: any authenticated identity — including a self-issued did:key caller or a relayed identity-token caller (COG-3 §6) — has the standing of its own capabilities, and the public ceiling does not apply.

OAuth Login

Venues MAY configure OAuth 2.0 Authorization Code flow providers to enable browser-based login. The following providers are supported:

Google

SettingValue
Authorization endpointhttps://accounts.google.com/o/oauth2/v2/auth
Token endpointhttps://oauth2.googleapis.com/token
JWKS URIhttps://www.googleapis.com/oauth2/v3/certs
Issuerhttps://accounts.google.com
Scopesopenid email profile

Google returns an OpenID Connect ID token. The venue verifies it via JWKS and extracts user identity.

Microsoft

SettingValue
Authorization endpointhttps://login.microsoftonline.com/common/oauth2/v2.0/authorize
Token endpointhttps://login.microsoftonline.com/common/oauth2/v2.0/token
JWKS URIhttps://login.microsoftonline.com/common/discovery/v2.0/keys
IssuerVaries by tenant
Scopesopenid email profile

Microsoft uses the common (multi-tenant) endpoint. The issuer varies by Azure AD tenant, so issuer validation is skipped.

GitHub

SettingValue
Authorization endpointhttps://github.com/login/oauth/authorize
Token endpointhttps://github.com/login/oauth/access_token
User info endpointhttps://api.github.com/user
JWKS URIN/A (GitHub does not issue JWTs)
Scopesuser:email read:user

GitHub uses standard OAuth 2.0 (not OpenID Connect). After token exchange, the venue fetches user information from GitHub's API.

OAuth Callback Flow

  1. The user visits /auth/{provider} and is redirected to the provider's authorisation page
  2. After consent, the provider redirects to /auth/{provider}/callback with an authorisation code
  3. The venue exchanges the code for tokens at the provider's token endpoint
  4. The venue extracts user identity (email, name, subject) from the ID token or user info endpoint
  5. The venue creates or updates the user record in its user database
  6. The venue issues a venue-signed JWT and returns it to the client

Redirect URIs

OAuth redirect URIs are constructed from the venue's base URL:

{baseUrl}/auth/{provider}/callback

The base URL is derived from the venue's hostname and port configuration, or can be set explicitly with the baseUrl venue configuration key. The redirect URI MUST be registered in the provider's developer console.

User Identity

After OAuth login, users are assigned a venue-managed DID formed from the venue's did:web identity (COG-2):

did:web:{venue-host}:u:{user-id}

This is a standard did:web DID — the colon-separated segments are the method's path encoding — and it resolves to a DID document the venue serves at https://{venue-host}/u/{user-id}/did.json. The venue is the controller of the DID and signs assertions about the user with its own key pair. A public venue hostname is required.

The user ID is derived from the email address by replacing . and @ with _ (e.g. alice@gmail.com becomes alice_gmail_com). When no email is available, the OAuth sub claim is used directly. User IDs MUST match [A-Za-z0-9._-]+.

User records are stored in the venue's user database with fields including did, email, name, provider, and updated timestamp.

Configuration

Authentication is configured in the venue configuration file under the auth key:

"auth": {
// Allow unauthenticated access (default: true)
"public": { "enabled": true }, // add "caps": [...] to widen the public capability ceiling

// JWT token expiry in seconds (default: 86400 = 24 hours)
"tokenExpiry": 86400,

// OAuth login providers
"oauth": {
"google": { "clientId": "...", "clientSecret": "..." },
"microsoft": { "clientId": "...", "clientSecret": "..." },
"github": { "clientId": "...", "clientSecret": "..." }
}
}

All fields are optional. A venue with no auth configuration allows anonymous access and has no login providers.

Security Considerations

Token Security

  • Bearer tokens SHOULD be transmitted only over HTTPS in production
  • Venue-signed JWTs SHOULD use short expiry times appropriate to the deployment context
  • Client secrets for OAuth providers MUST NOT be committed to version control or exposed in client-side code

Self-Issued Token Trust

Self-issued EdDSA tokens prove that the caller controls a key pair, but do not establish any real-world identity. Venues that require identity assurance SHOULD use OAuth login and restrict access to venue-signed tokens.

JWKS Caching

The venue caches JWKS responses from external providers to avoid excessive network requests. Cached keys are refreshed periodically or when a kid is not found in the cache.

Anonymous Access

When public access is enabled, the venue MUST NOT assume that anonymous requests are trustworthy. Application-level access control SHOULD be applied to restrict what anonymous callers can do.