Released docs. You are viewing the documentation published with v0.34.0. Development docs are available at Latest.
Control who can request Evidence Gateway
For the assertion provider
Complete Return a governed value before starting this tutorial. You will give two applications different access to that Evidence Gateway service, add one while the service is running, and prove that a valid access token does not let its client ask every configured question.
Understand what you are controlling
Section titled “Understand what you are controlling”This tutorial manages access for machine applications, not accounts for people.
The pinned local issuer authenticates each application from its own key and issues a short-lived access token. Evidence Gateway then checks whether the application’s access policy includes the configured question. These are separate decisions:
| Decision | Example | Owner |
|---|---|---|
| Which application is calling? | age-checker | Local issuer client registration |
| What may it ask? | The age-checks policy includes adult-status | Evidence Gateway access policy |
| May Evidence Gateway read its source? | GET /people/{person_id} | Evidence Gateway source configuration |
| May a consumer trust the result? | Expected issuer, audience, and signing key | Consumer verification policy |
The first two rows are the access-management boundary you will configure. Source credentials and consumer trust remain independent.
Access policies are part of Evidence Gateway’s immutable governed configuration. Client membership is part of the local issuer generation:
| Change | Runtime effect |
|---|---|
| Add or revoke a client | Stop the local session, change the reviewed registry, and start a new generation |
| Add a question or change an access policy | Start a new Evidence Gateway generation |
A client change affects the next local generation. Stopping that generation also stops its issuer.
Restart the source mock
Section titled “Restart the source mock”In one terminal, return to the working directory from the first tutorial and serve the checked synthetic cases:
evidencectl source mock serve --config adult-status/mocks/source.yamlLeave the source mock running. In another terminal, enter the project containing both questions:
cd adult-statusThe project has these two governed questions:
| Question | Declared purpose | Answer |
|---|---|---|
adult-status | age-check | Boolean adult status |
age-bracket | service-path-selection | One reviewed age bracket |
An access policy names one or more questions. Each question already fixes its purpose, subject shape, source, and possible answers, so you do not repeat those fields in the policy.
Define two access policies
Section titled “Define two access policies”Define a policy for each service task:
evidencectl access policy add age-checks --question adult-statusevidencectl access policy add service-routing --question age-bracketAdded access policy age-checks for adult-status.Added access policy service-routing for age-bracket.Review the governed policies before starting Evidence Gateway:
evidencectl access policy listThe command prints a tab-separated POLICY and QUESTIONS table, one row per policy: age-checks
holding adult-status, and service-routing holding age-bracket.
The commands write the reviewable policy documents to access/policies/age-checks.yaml and
access/policies/service-routing.yaml.
Many clients can share one policy. A client can also belong to several policies when their question
sets do not overlap. evidencectl rejects overlapping policy assignments because they would make
the access decision ambiguous. Adding a question to either policy later changes the governed
authorization boundary and requires a new Evidence Gateway generation.
Register the first local application
Section titled “Register the first local application”Register age-checker under the age-checks policy:
evidencectl access client add age-checker \ --policy age-checks \ --generate-local-keyAdded client age-checker with policy age-checks.--generate-local-key keeps this tutorial self-contained. The private key represents the
application’s identity and remains owner-only at
.evidence/clients/age-checker/private.jwk. The reviewable registration at
access/clients/age-checker.yaml contains the policy membership and public key, never the private
key.
Start the protected service
Section titled “Start the protected service”Compile the questions and both access policies, then start Evidence Gateway and its local issuer:
evidencectl dev start .Evidence ready at http://127.0.0.1:8080Issuer ready at http://127.0.0.1:8081The local issuer recognizes age-checker. Evidence Gateway has both access policies available, even though
no client belongs to service-routing yet.
Make an allowed request
Section titled “Make an allowed request”Prepare an adult-status request as age-checker:
evidencectl request prepare adult-status \ --purpose age-check \ --subject person_id=person-123 \ --client age-checker \ --name age-checker-allowedThe Evidence client prepares the request and closes its pinned verification expectations locally.
evidencectl separately signs a one-time client assertion with the local application key and
exchanges it with the local issuer for a short-lived access token. Preparation sends no HTTP request
to Evidence Gateway and performs no source access.
Send the request across the Evidence Gateway HTTP boundary:
curl --silent --show-error --fail-with-body \ --config .evidence/requests/age-checker-allowed/authorization.curl \ --request POST \ --url http://127.0.0.1:8080/v1/evidence \ --header 'Content-Type: application/json' \ --header 'Accept: application/jose+json' \ --data-binary @.evidence/requests/age-checker-allowed/request.json \ --output age-checker-allowed.jws.json \ --write-out 'HTTP %{http_code}\n'HTTP 200Verify the response before reading it:
evidencectl verify age-checker-allowed.jws.json \ --context .evidence/requests/age-checker-allowed/verification.json \ --output age-checker-allowed.verified.jsonVERIFIEDThe application was authenticated, its age-checks policy matched the request, and Evidence Gateway
called the registry only after both checks passed.
Add an application for the next generation
Section titled “Add an application for the next generation”Stop the current session, then register service-router under the existing service-routing
policy:
evidencectl dev stopevidencectl access client add service-router \ --policy service-routing \ --generate-local-keyAdded client service-router with policy service-routing.The command writes the public registration to access/clients/service-router.yaml, keeps the
private key under .evidence/clients/, and leaves the stopped generated session unchanged. Start a
fresh generation so Evidence Gateway and the issuer consume one validated snapshot:
evidencectl dev start .Review the active client assignments:
evidencectl access client listThe command prints a tab-separated CLIENT, STATUS, and POLICIES table. Both age-checker and
service-router are active, each under the single policy it was registered with.
Use the application assigned the policy
Section titled “Use the application assigned the policy”Prepare an age-bracket request as service-router:
evidencectl request prepare age-bracket \ --purpose service-path-selection \ --subject person_id=person-456 \ --client service-router \ --name service-router-allowedSend and verify the response:
curl --silent --show-error --fail-with-body \ --config .evidence/requests/service-router-allowed/authorization.curl \ --request POST \ --url http://127.0.0.1:8080/v1/evidence \ --header 'Content-Type: application/json' \ --header 'Accept: application/jose+json' \ --data-binary @.evidence/requests/service-router-allowed/request.json \ --output service-router-allowed.jws.json \ --write-out 'HTTP %{http_code}\n'
evidencectl verify service-router-allowed.jws.json \ --context .evidence/requests/service-router-allowed/verification.json \ --output service-router-allowed.verified.jsonHTTP 200VERIFIEDThe successful token exchange proves that the new issuer generation accepted the client registry.
service-router belongs to the policy required for this question. Preparation made zero Evidence
Gateway HTTP requests, curl made the single POST /v1/evidence assertion request, and
evidencectl verify checked the response offline.
Try a question the application was not granted
Section titled “Try a question the application was not granted”Prepare the same age-bracket request using the age-checker identity:
evidencectl request prepare age-bracket \ --purpose service-path-selection \ --subject person_id=person-456 \ --client age-checker \ --name age-checker-refusedThe command can prepare the request because age-bracket is a valid project question and
age-checker is a registered client. The client preparation path closes the request and its
verification expectations without calling Evidence Gateway or deciding whether this application
may ask the question. The local issuer only issues the token. Evidence Gateway makes the authorization
decision when you send the request.
Send the request:
curl --silent --show-error \ --config .evidence/requests/age-checker-refused/authorization.curl \ --request POST \ --url http://127.0.0.1:8080/v1/evidence \ --header 'Content-Type: application/json' \ --header 'Accept: application/jose+json' \ --data-binary @.evidence/requests/age-checker-refused/request.json \ --output age-checker-refused.json \ --write-out 'HTTP %{http_code}\n'HTTP 403Inspect the safe problem response:
python3 -m json.tool age-checker-refused.json{ "type": "https://id.registrystack.org/problems/registry-evidence/evidence/denied", "title": "Evidence request is not permitted", "status": 403, "detail": "the Evidence request is not permitted", "code": "evidence.denied", "traceId": "<32-lowercase-hex-trace-id>"}The access token is valid, but the client’s age-checks policy does not authorize the
age-bracket question. Changing only the authenticated application changes the access decision.
The registry terminal shows no new GET /people/person-456, because Evidence Gateway refuses the
request before source access. The response does not reveal which application, question, or policy
caused the refusal.
Revoke an application
Section titled “Revoke an application”Stop the generation after the refusal and inspect its completed audit chain before replacing it:
evidencectl dev stopevidencectl audit show --last-operationLocal Evidence stoppedACCESS REFUSED requester=<pseudonym> reason=not_authorizedThe privacy-safe refusal event contains a requester pseudonym and the closed not_authorized
reason. It does not contain the rejected requirement, purpose, selector, authority, response format,
client identifier, or access token.
Revoke age-checker while the session is stopped, then start the next generation:
evidencectl access client revoke age-checkerevidencectl dev start .Revoked client age-checker.Evidence ready at http://127.0.0.1:8080Issuer ready at http://127.0.0.1:8081The command updates access/clients/age-checker.yaml. The next issuer generation excludes the
revoked client.
Try to prepare a fresh request as the revoked client:
evidencectl request prepare adult-status \ --purpose age-check \ --subject person_id=person-123 \ --client age-checker \ --name age-checker-revokedevidencectl: unknown or revoked active client age-checkerevidencectl rejects an unknown or revoked named client locally, before contacting the issuer
or publishing request artifacts. service-router remains registered and keeps its
service-routing membership.
Stop the final generation
Section titled “Stop the final generation”Stop the local services:
evidencectl dev stopLocal Evidence stoppedThe revoked-client preparation remains local and creates no Evidence Gateway audit event because no HTTP request was sent.
Clean up
Section titled “Clean up”Remove the stopped generated runtime while preserving the editable questions, access policy, and request artifacts:
evidencectl dev cleanReturn to the registry terminal and press Ctrl+C.
What you proved
Section titled “What you proved”- Authentication identifies the calling application but grants no question by itself.
- Many applications can share a governed access policy without client-specific Evidence Gateway config.
- A client registry change takes effect only through one newly validated local generation.
- Each application receives only the questions included in its assigned policies.
- Evidence Gateway refuses unauthorized questions before reading the source.
- Evidence Gateway retains a privacy-safe audit event for an authenticated authorization refusal.
- Revoking a local client excludes it from the next issuer generation and prevents local request preparation.
- Adding a question or changing an access policy requires a new Evidence Gateway generation.
- Source authentication and consumer trust remain separate from caller access.