Skip to main content

COG-3: Authentication

Status:      Draft
Version: 2.0
Created: 2025-09-24
Updated: 2026-01-28
Authors: Mike Anderson

Purpose

Authentication ensures the integrity, security, and controlled access to assets and operations on the grid. This document specifies authentication mechanisms for venues, enabling secure and flexible access control while maintaining venue operators' autonomy over access policies.

Authentication is managed at a per-venue level, allowing venue operators to define and enforce access policies tailored to their specific requirements.

Authentication mechanisms are built on commonly available web standards and, where appropriate, make use of decentralised facilities supported by Convex lattice technology.

Principles

  • Venue autonomy — Each venue operator decides which authentication mechanisms to support and what privileges to grant.
  • Layered security — Multiple mechanisms MAY be supported simultaneously, allowing clients to use whichever is appropriate.
  • Standards-based — All mechanisms use established web and cryptographic standards.
  • Decentralisation-ready — Ed25519 key-based authentication ties into the broader Convex identity model without requiring centralised credential stores.

Specification

1. Public Access (No Authentication)

Venues MAY provide open, public access to grid operations and assets, enabling public services or sharing open-source capabilities without requiring prior authorisation.

Public access is the simplest mode and is appropriate for open data, demo services, and community resources.

Venues SHOULD NOT allow unauthorised users to consume excessive resources.

Venues SHOULD implement rate limiting on public endpoints, e.g. via a reverse proxy or application-level throttling.

2. Bearer Token (API Key)

Venues MAY offer authorisation using bearer tokens (commonly referred to as API keys).

The token MUST be passed by the client with every HTTPS request using the standard Authorization header:

Authorization: Bearer <token>

If the venue offers bearer-token authorisation, it has complete control over what privileges it grants to clients using any particular token. Token provisioning is out of scope for this specification and is managed by the venue operator (e.g. via a management portal, CLI, or out-of-band exchange).

Security considerations

  • Tokens MUST be treated as secrets and MUST NOT be logged, committed to version control, or transmitted over unencrypted channels.
  • Venues SHOULD support token revocation.
  • Venues SHOULD enforce token expiry where appropriate.

3. HTTP Basic Authentication

Venues MAY support HTTP Basic authentication as defined in RFC 7617.

Credentials are transmitted as a Base64-encoded username:password pair in the Authorization header:

Authorization: Basic <base64(username:password)>

Basic authentication MUST only be used over HTTPS to protect credentials in transit.

This mechanism is suitable for simple setups, internal tooling, or development environments where a lightweight credential model is sufficient.

4. OAuth 2.0

Venues MAY allow authentication using OAuth 2.0 with PKCE (RFC 7636).

OAuth enables delegated authorisation, allowing users to authenticate via an external identity provider (e.g. Google, GitHub, or a corporate IdP) without sharing their credentials with the venue.

Flow overview

  1. Client initiates an authorisation request to the venue's OAuth endpoint.
  2. Venue redirects the client to the identity provider for authentication.
  3. On successful authentication, the identity provider returns an authorisation code to the venue callback.
  4. The venue exchanges the code for an access token.
  5. The client uses the access token as a bearer token for subsequent API requests.

Requirements

  • Venues implementing OAuth MUST use PKCE to mitigate authorisation code interception attacks.
  • Access tokens SHOULD be short-lived; refresh tokens MAY be issued for long-lived sessions.
  • Venues MUST validate tokens on every request.

5. Ed25519 Self-Issued JWT

Venues MAY authenticate clients using self-issued JWTs signed with Ed25519 keys. This mechanism aligns with the Convex identity model, where accounts are identified by Ed25519 public keys, and with the W3C did:key method for self-sovereign identity.

The client's identity is a did:key DID derived from their Ed25519 public key. No pre-registration is required — any entity with an Ed25519 key pair can authenticate. The venue verifies the JWT signature by extracting the public key from the did:key in the token's iss claim.

Client identity: did:key

The client's DID is computed from the Ed25519 public key using the did:key method:

  1. Take the 32-byte Ed25519 public key
  2. Prepend the multicodec prefix 0xed01 (Ed25519 public key)
  3. Encode with multibase base58btc (prefix z)
  4. Result: did:key:z6Mk...

This DID is self-certifying — the public key is embedded in the identifier itself, requiring no external resolution.

JWT structure

The client constructs a JWT with the following structure:

Header:

{
"alg": "EdDSA",
"typ": "JWT",
"kid": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
}

Payload:

{
"iss": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"sub": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK",
"aud": "did:web:venue.example.com",
"iat": 1706367600,
"exp": 1706367900
}
ClaimRequiredDescription
issREQUIREDClient's did:key DID
subREQUIREDSame as iss (self-issued token)
audRECOMMENDEDVenue DID or URL — prevents replay at a different venue
iatREQUIREDIssued-at timestamp (Unix seconds)
expREQUIREDExpiry timestamp (Unix seconds)
jtiOPTIONALUnique token ID for replay detection

The kid header parameter MUST match the iss claim and identifies the verification key.

Transport

The JWT is sent using the standard Authorization: Bearer header:

Authorization: Bearer eyJhbGciOiJFZERTQSIs...

This reuses the same header as bearer tokens and API keys. The venue distinguishes a self-issued JWT from an opaque token by decoding the JWT and checking for alg: EdDSA with a did:key issuer.

Flow overview

Client                                        Venue
│ │
│ 1. Generate Ed25519 key pair (once) │
│ did:key:z6Mk... = encode(pubkey) │
│ │
│ 2. Create JWT: │
│ iss: did:key:z6Mk... │
│ aud: did:web:venue.example.com │
│ exp: <now + 5min> │
│ Sign with Ed25519 private key │
│ │
│ Authorization: Bearer <JWT> │
│ POST /api/v1/invoke │
│ ───────────────────────────────────────────▶ │
│ │
│ 3. Decode JWT, extract did:key from iss
│ 4. Derive Ed25519 pubkey from did:key
│ 5. Verify JWT signature
│ 6. Validate exp, aud, iat
│ 7. (Optional) Resolve Convex account
│ │
│ 200 OK │
│ ◀─────────────────────────────────────────── │

Venue verification

Venues MUST perform the following validation steps:

  1. Decode the JWT and verify alg is EdDSA
  2. Extract the did:key from the iss claim
  3. Decode the Ed25519 public key from the did:key (reverse multicodec + multibase)
  4. Verify the JWT signature using the extracted public key
  5. Validate exp > now (reject expired tokens)
  6. Validate iat <= now + clock_skew (reject tokens issued in the future)
  7. If aud is present, validate it matches the venue's own DID or URL
  8. Validate exp - iat <= max_lifetime (reject tokens with excessively long validity)

Recommended validation parameters:

ParameterRecommended value
Clock skew tolerance30 seconds
Maximum token age (now - iat)10 minutes
Maximum token lifetime (exp - iat)5 minutes

Token lifetime

Tokens SHOULD be short-lived (recommended 5 minutes). Since the client holds the private key, generating a new JWT is effectively free (Ed25519 signing takes microseconds). Refresh tokens are unnecessary — when a token expires, the client simply signs a new one.

Optional Convex account resolution

After verifying the JWT signature, a venue MAY look up the Ed25519 public key on the Convex network to resolve a Convex account:

  1. Extract the 32-byte Ed25519 public key from the did:key
  2. Query the Convex network for accounts whose controller key matches
  3. If found — associate the request with the Convex account (e.g. #1337)
  4. If not found — the client is authenticated by did:key alone

This resolution is a venue-side decision. The client does not need to be aware of it. A venue not connected to the Convex network simply authenticates by did:key without account resolution.

Security considerations

  • Private keys MUST NOT leave the client and MUST NOT be transmitted over the network.
  • The exp and aud claims provide replay protection without server-side state.
  • Venues SHOULD reject tokens where exp - iat exceeds the maximum lifetime, preventing clients from creating excessively long-lived tokens.
  • For high-security environments, venues MAY track jti values within the token's validity window to detect replay of the exact same token.
  • This mechanism integrates naturally with Convex account keys, enabling on-chain identity verification.

Client SDK Support

The Covia SDKs provide a generic authentication interface that supports all mechanisms described above.

MechanismPython SDKJava SDK
Public (no auth)DefaultDefault
Bearer tokenBearerAuth(token)Supported
HTTP BasicBasicAuth(user, pass)Supported
OAuth 2.0PlannedSupported
Ed25519 JWTEd25519AuthPlanned

Python SDK example

from covia import Grid
from covia.auth import BearerAuth, BasicAuth

# Public access (no auth)
venue = Grid.connect("https://venue.covia.ai")

# Bearer token
venue = Grid.connect("https://venue.covia.ai", auth=BearerAuth("my-token"))

# HTTP Basic
venue = Grid.connect("https://venue.covia.ai", auth=BasicAuth("user", "pass"))
# Ed25519 self-issued JWT (requires: pip install covia[signing])
from covia.auth import Ed25519Auth

# Generate a new identity — audience is auto-set from Grid.connect()
auth = Ed25519Auth.generate()
print(auth.did) # did:key:z6Mk...
venue = Grid.connect("did:web:venue.covia.ai", auth=auth)

# Or from a known seed (deterministic key)
auth = Ed25519Auth.from_seed(seed_bytes)
venue = Grid.connect("did:web:venue.covia.ai", auth=auth)

Custom authentication providers can be implemented by subclassing covia.auth.Auth:

from covia.auth import Auth

class ApiKeyAuth(Auth):
def __init__(self, key: str) -> None:
self._key = key

def apply(self, headers: dict[str, str]) -> None:
headers["X-Api-Key"] = self._key

Venue Discovery

Venues SHOULD advertise their supported authentication mechanisms via the A2A agent card (/.well-known/agent-card.json) using the securityScheme field. This allows clients to discover the required authentication method before making API calls.

References