Grant and Revoke
Check whether the commands are available
The Agent reads Inspect before calling either command. commands.supported must name the command, and commands.grant_types must contain the requested credential type. If the grant-type list is absent or empty, the Service cannot advertise Grant or Revoke. The Agent must not infer command support from an authentication method advertised for protected resources.
Grant also requires an existing enrollment recognized by the Service. When the Agent does not know its current state, it should call Status before starting credential issuance. The Service must reject Grant for an unrecognized Agent with not_recognized; Grant never creates an enrollment as a side effect.
Issue a credential with Grant
The Agent sends POST to the Grant path under the Service's advertised http.endpoint_base. It signs a fresh baseline assertion with op=grant, sends a non-empty Idempotency-Key, and names an advertised grant_type in the JSON body. This illustrative Service uses /aep/ as its endpoint base and offers api-key:
POST /aep/grant HTTP/1.1
Host: api.example.com
Content-Type: application/aep+json
Authorization: AEP <jwt>
Idempotency-Key: 7e2bdbd7-165e-4c35-9f11-9376e314e617
{"grant_type":"api-key"}The selected grant-type specification may require additional request fields and defines the successful response's usable secret, expiry, and presentation rules. Every successful response is a JSON object containing that credential material and a stable Service-issued credential_id. The identifier is unique across all credentials issued by that Service, including different Agents and grant types, and is never reassigned. Its logical identity is the Service DID paired with credential_id. It is a management identifier, not the secret presented to a protected resource.
Choose what Revoke invalidates
Revoke uses POST under the same advertised endpoint base, but its baseline assertion has op=revoke. This request invalidates all API-key credentials issued to the authenticated Agent, not credentials issued to other Agents:
POST /aep/revoke HTTP/1.1
Host: api.example.com
Content-Type: application/aep+json
Authorization: AEP <jwt>
Idempotency-Key: 156572f4-2cfb-40e6-8f3d-4db4f588b42b
{"grant_type":"api-key"}The request body selects one of three scopes. The all_grant_types value is the JSON string "true", not a JSON boolean. It cannot be combined with either of the other fields.
| Target | Request fields and support |
|---|---|
| One grant type | grant_type alone revokes every matching credential issued to this Agent. |
| One credential | grant_type plus credential_id is permitted only when commands.grant_types_config advertises supports_per_credential_revoke as "true" for that type. |
| Every grant type | "all_grant_types":"true" revokes every session credential issued to this Agent. Every Service supporting Revoke supports this scope. |
A successful Revoke returns 200 OK with an empty JSON object, {}, even if no matching credential existed. The Agent should remove the targeted credential from local storage after success. The Revoke credentials guide helps an Agent choose the appropriate scope.
Authenticate and retry safely
Grant and Revoke always use the baseline Authorization: AEP <jwt> form with the operation appropriate to the command. A session credential cannot authenticate either command. The Service verifies the assertion independently on each request, including a retry; a retry needs a fresh assertion and replay identifier, while its idempotency key stays the same.
Both state-changing commands require a non-empty Idempotency-Key header. The Service retains the result for the authenticated Agent and key for at least one hour, bound to the command and request body. Retrying the same command and body with that key returns the cached response or an equivalent success; using it for another command or body returns 409 idempotency_conflict. A missing or empty key returns 400 invalid_request. Use a new key for a new operation.
Interpret failure without guessing
401 not_recognized covers an unrecognized Agent and other failed assertion checks without disclosing which check failed. 400 unsupported_grant_type means the requested type was not advertised. 400 invalid_request covers malformed field combinations, including an all_grant_types request mixed with grant_type or credential_id. Do not retry the same rejected request without correcting its cause.
For the full Problem Details and retry contract, see Errors and idempotency. For the concrete credential fields, continue with API key, Basic, or OAuth Bearer.