Expand description
§aep-service
aep-service provides the framework-neutral Service implementation for the Agent Enrollment
Protocol. It builds the Inspect document, verifies client assertions, enforces replay and
idempotency rules, manages enrollment lifecycle state, dispatches Grant and Revoke handlers, and
authenticates protected resources.
§Install
[dependencies]
aep-service = "0.2"§Create a Service
use std::{sync::Arc, time::Duration};
use aep_service::{
DidWebClientAssertionVerifier, ReqwestTransport, Service, ServiceOptions,
};
let transport = Arc::new(ReqwestTransport::new(
1 << 20,
Duration::from_secs(10),
)?);
let verifier = Arc::new(DidWebClientAssertionVerifier::new(transport, false));
let options = ServiceOptions::new("did:web:service.example", verifier);
let service = Service::new(options)?;The default Service supports Inspect, Enroll, and Status with in-memory enrollment, assertion
replay, and command-idempotency stores. Set ServiceOptions fields to advertise Claims,
authentication methods, Grant Types, OpenAPI metadata, and extensions. Replace the memory stores
with durable implementations before running more than one process or retaining state across
restarts.
§Connect HTTP routes
Use aep-axum for direct Axum integration or aep-tower for a
reusable Tower Service and authentication layer. Both adapters are optional.
When integrating another HTTP stack, expose service.inspect_document() at /.well-known/aep.
Route the four authenticated commands to Service::enroll, Service::status, Service::grant,
and Service::revoke. Each command returns a ServiceResponse containing the HTTP status, headers,
and a typed ResponseBody; use ResponseBody::to_json() for the wire body.
The aep-service-axum example mounts every command and protects
an application resource. The aep-local-lifecycle example
shows the direct Service boundary without a web framework.
Enroll, Grant, and Revoke require a non-empty Idempotency-Key value through
IdempotentCommandOptions. Status uses AuthenticatedCommandOptions. The application adapter is
responsible for extracting the AEP client assertion and idempotency header from the incoming
request without logging either value.
The memory command-idempotency store retains completed responses for one hour after execution completes. A failed operation releases its key for a retry; an exact retry of a completed operation returns the stored response. Custom stores must retain responses for at least one hour and bind each key to its Agent, command and request body. A command retry keeps its idempotency key but uses a fresh client assertion; assertion replay protection also applies to retries.
Call Service::authenticate_protected_resource before serving an authenticated application
resource. It accepts typed headers, method, and URL and returns either an AuthenticatedPrincipal
or the complete 401 AEP challenge response.
The default ReqwestTransport requires Tokio and TLS 1.3 or later for HTTPS. Applications using
another runtime supply an HttpTransport with equivalent HTTPS, redirect and response-size controls.
§Grant Types
Register each advertised Grant Type with a GrantTypeDefinition and a GrantTypeHandler. The
handler issues a JSON object containing a non-empty, globally unique credential_id, revokes the
credential targets described by RevokeRequest, and may authenticate its credential presentation
at protected resources. A Service does not advertise Grant or Revoke when no Grant Types are
configured.
For built-in credentials, use stored_api_key_grant_type, stored_basic_grant_type, or
stored_oauth_bearer_grant_type with an issuer callback and a ServiceCredentialStore.
The issuer supplies credential material, expiry, and a unique identifier; API-key secrets and
Basic passwords require at least 128 bits of entropy. The memory store retains one-way secret
verifiers. A custom store receives usable credentials in save. API-key stores must retain
salted hashes or equivalent one-way verifiers; Basic stores must apply strong password-storage
controls. Protect stored records, honor expiry and revocation, and do not log credential material.
The application remains responsible for authorizing resource access using the returned principal
and scopes.
§Verification boundary
DidWebClientAssertionVerifier performs real EdDSA or ES256 verification after resolving the
assertion key from the Agent’s did:web document. Supply an alternate ClientAssertionVerifier
for a different supported identity or hosted verification boundary. The Service independently
checks audience, operation, resource, validity window, identity method, and atomic replay
consumption after verification.
§Hosted Platform verification
HostedPlatformClientAssertionVerifier calls a trusted Platform’s verification endpoint using
the Service’s own Platform credential. The Platform’s Authorizer must permit that Service to
verify assertions for its Service DID. The Service does not need to own the Agent identity, and
verification permission does not grant signing or lifecycle-management permission.
use std::sync::Arc;
use aep_service::{
HostedPlatformClientAssertionVerifier, HostedPlatformClientAssertionVerifierOptions,
Service, ServiceOptions,
};
let mut options = HostedPlatformClientAssertionVerifierOptions::new(
"https://platform.example/v1/aep/verifications",
);
options.authorization = Some("Bearer service-platform-token".to_owned());
let verifier = Arc::new(HostedPlatformClientAssertionVerifier::new(options)?);
Service::new(ServiceOptions::new("did:web:api.example.com", verifier))?;The default HTTP transport uses TLS 1.3, refuses redirects, and limits responses to 1 MiB.
request_timeout defaults to 30 seconds and bounds injected transports too. Custom transports
must enforce TLS 1.3, avoid redirects, and bound response reads. Configure a trusted endpoint;
the Agent’s assertion does not choose where the Service sends its Platform credential.
The verification request’s idempotency key is derived from its complete body, not the Service command’s idempotency key. An exact verification retry uses the same key; a fresh assertion uses a new key. The Service still checks the returned claims and consumes its own replay record, so a cached Platform verification cannot authenticate the same assertion twice at the Service.
Hosted verification is optional. Keep local did:web verification available as required by the
AEP draft; the application selects its verification policy. This helper does not automatically
fall back to local verification when a Platform refuses or cannot complete a request.
See the workspace guide and the AEP specifications.
Structs§
- Authenticated
Command Options - Authenticated
Principal - Claim
Value Limits - The bounds a Service places on the Claim Values it will accept.
- Claims
Configuration - Client
Assertion Replay Record - Client
Assertion Verification Context - Command
Idempotency Input - Command
Idempotency Record - Credential
Authentication Input - Credential
Match - DidWeb
Client Assertion Verifier - Enrollment
Decision - Enrollment
Record - Grant
Context - Grant
Type Definition - Hosted
Platform Client Assertion Verifier - Hosted
Platform Client Assertion Verifier Options - Idempotent
Command Options - Memory
Client Assertion Replay Store - Memory
Command Idempotency Store - Memory
Enrollment Store - Memory
Service Credential Store - Open
ApiConfiguration - Protected
Resource Request - Reqwest
Transport - Service
- Service
Credential Record - Service
Options - Service
Response - Static
Enrollment Policy - Stored
Credential Grant Type Options - System
Clock
Enums§
- Authentication
Kind - Command
Idempotency Result - Idempotent
Command - Protected
Resource Authentication - Response
Body - Service
Error
Traits§
- Client
Assertion Replay Store - Client
Assertion Verifier - Clock
- Command
Idempotency Store - Enrollment
Policy - Enrollment
Store - Grant
Type Handler - Service
Credential Store