Skip to main content

COG-10: Authentication

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

This specification is under active development. Structure and details may change significantly based on implementation experience and community feedback.

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 Token: A JWT presented in the Authorization: Bearer <token> HTTP header
  • 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:...)

├── 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.

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.

Requirements:

  • The JWT MUST use the EdDSA algorithm
  • The kid header MUST contain the signer's public key encoded as a Multikey string
  • The sub claim MUST be a did:key URI whose public key matches the kid header
  • The JWT MUST include iat (issued at) and exp (expiration) claims
  • The venue verifies the signature using the public key from the kid header, then confirms that the sub claim's did:key encodes the same key

Example claims:

{
"sub": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"iat": 1706500000,
"exp": 1706586400
}

This mechanism requires no prior registration or shared secrets. Any entity with an Ed25519 key pair can authenticate to any venue. The did:key in the sub claim serves as the caller's decentralised identifier.

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:covia:local: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:covia:local:u:alice_gmail_com",
"iss": "did:covia:local",
"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.

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 authorization page
  2. After consent, the provider redirects to /auth/{provider}/callback with an authorization 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-scoped DID:

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

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 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 },

// 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.