Example

Protected-resource access

Trace one Agent request from an anonymous order lookup through a Service challenge, a resource-bound assertion, and the application response.

What this exchange assumes

The Agent has an identity recognized by api.example.com and wants to read order 123. The Service protects that route with AEP and advertises aep-jwt for protected resources. This example uses a bodyless GET, so the Agent can reproduce the request exactly after a challenge. It does not use a session credential, OpenAPI preflight, or payment.

The messages below illustrate the AEP boundary. The Service's order representation and its decision about whether this Agent may read it belong to the application, not to AEP. For a reusable client flow that also handles request bodies and payment, read Protected-resource access.

01agent

Request the order and receive a challenge

The Agent first sends the requested operation without an AEP credential:

GET /v1/orders/123 HTTP/1.1
Host: api.example.com

The protected route requires authentication, so the Service returns an AEP challenge instead of order data:

HTTP/1.1 401 Unauthorized
Content-Length: 0
WWW-Authenticate: AEP service_did="did:web:api.example.com",inspect="https://api.example.com/.well-known/aep",reason="authentication_required"

The service_did names the Service; inspect tells the Agent where to discover its methods. The reason explains this challenge. An unrelated 401, or one without both discovery parameters, does not start an AEP authentication flow.

02agent

Check the Service before requesting an assertion

The Agent fetches Inspect anonymously, without copying credentials or caller headers from the order request. It checks that the challenged DID matches Inspect service.did and that the DID is bound to the final Inspect response origin. The relevant fields in this example are:

{
  "authentication": {"methods": ["aep-jwt"]},
  "service": {"did": "did:web:api.example.com"}
}

This is an Inspect fragment, not the complete document. Because aep-jwt is advertised, the Agent can use a client assertion with op=authenticate for this protected route. The baseline assertion used for Enroll or Status would have the wrong operation. If the DID or origin check fails, the Agent stops before asking its signer for an assertion or sending a credential.

03agent

Sign for this exact resource

The Agent signs a fresh client assertion. These illustrative claims bind the Agent identity, Service, operation, and precise request target:

{
  "iss": "did:web:agent.example.com:agents:123",
  "sub": "did:web:agent.example.com:agents:123",
  "aud": "did:web:api.example.com",
  "op": "authenticate",
  "resource": "https://api.example.com/v1/orders/123",
  "iat": 1783958400,
  "exp": 1783958460,
  "jti": "7f22558c-b4de-4f6e-9f6c-e3fbacc034b9"
}

iss and sub identify the same Agent; aud is the Service DID. resource identifies the normalized absolute HTTPS target, not just its path. The numeric iat and exp values show a one-minute interval, and jti is a single-use replay identifier. These fixed values are illustrative, not credentials to copy; a real assertion needs a new jti, current times, a suitable JOSE header, and a signature using an algorithm the Service advertises.

04agent

Retry and let the application decide

The Agent retries the same method and target with the newly signed assertion in the ordinary Authorization field:

GET /v1/orders/123 HTTP/1.1
Host: api.example.com
Authorization: AEP <signed-client-assertion>

The bracketed value is a placeholder, not a usable JWT. The Service performs full client-assertion verification, including the signature, Agent identity, audience, authenticate operation, resource binding, validity window, and unique jti. It then applies its own order-access policy. If that policy permits the read, one possible application response is:

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 12

{"id":"123"}

The JSON body is illustrative application data; AEP does not define an order response. A valid credential can still lead to 403 insufficient_scope if this Agent may not read the order. That is an application authorization failure after authentication, not a reason to repeat Enroll or try another assertion.

What changes if the resource redirects

If this route redirects on the same origin to /v1/orders/124, the Agent cannot reuse the assertion bound to order 123. It may follow only if the redirected request remains authorized, and it must sign a new assertion whose resource names the new target. It keeps the AEP credential carrier chosen for the operation.

If the target is on another origin, the Agent strips Authorization, AEP-Authorization, PAYMENT-SIGNATURE, and every AEP, session, or payment credential, including a Service-selected API-key header if one was used. It starts anonymously at the new origin and requires that origin's own valid AEP challenge before authenticating there. See Protected-resource authentication for the complete carrier, replay, and redirect contract.