Unreleased documentation. These pages follow the main branch and can change before the next release. For supported guidance, use v0.15.2.
See Evidence Gateway refuse unsafe requests
For the assertion provider and consumer or verifier
Complete Return a governed value before starting this tutorial. You will reuse that project to observe two boundaries: Evidence Gateway denies a purpose the provider did not authorize, and the verifier rejects a response changed after signing.
Restart the local boundary
Section titled “Restart the local boundary”In the terminal that owns the Python registry, return to the first-evidence-assertion directory
and start the source:
python3 registry.pyIn another terminal, enter the existing project and start a fresh local generation:
cd adult-statusevidencectl dev --detachEvidence Gateway ready at http://127.0.0.1:8080Mint ready at http://127.0.0.1:8081Prepare one authorized request
Section titled “Prepare one authorized request”Prepare a normal age-bracket request. This records the exact verification expectations before any response exists:
evidencectl request prepare age-bracket \ --purpose service-path-selection \ --subject person_id=person-123 \ --name refusal-checkThe provider configured service-path-selection for this question. Preparation also obtained a
short-lived local token carrying the tutorial caller’s configured authority claims. The token does
not authorize one exact request. Evidence Gateway applies those claims to the request it receives.
Change the purpose after preparation
Section titled “Change the purpose after preparation”Copy the request, then change only its purpose:
cp .evidence/requests/refusal-check/request.json unauthorized-request.jsonpython3 - <<'PY'import jsonfrom pathlib import Path
path = Path("unauthorized-request.json")request = json.loads(path.read_text())request["purpose"] = "age-check"path.write_text(json.dumps(request))PYThe retained authorization does not grant age-check for this requirement. Send the changed
request across the same HTTP boundary:
curl --silent --show-error \ --config .evidence/requests/refusal-check/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 @unauthorized-request.json \ --output unauthorized-response.json \ --write-out 'HTTP %{http_code}\n'HTTP 403Inspect the public problem:
python3 -m json.tool unauthorized-response.jsonThe response identifies only the closed not_authorized problem and an opaque operation ID. It
does not reveal source facts, selector values, grants, or credentials. The registry terminal shows
no new GET /people/person-123 because authorization failed before source access.
Obtain and verify the authorized response
Section titled “Obtain and verify the authorized response”Now send the unchanged prepared request:
curl --silent --show-error \ --config .evidence/requests/refusal-check/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/refusal-check/request.json \ --output authorized-response.jws.jsonVerify it against the expectations retained during preparation:
evidencectl verify authorized-response.jws.json \ --context .evidence/requests/refusal-check/verification.json \ --output authorized-response.verified.jsonVERIFIEDThis is the control case. The authorized, unchanged response is trusted.
Change the signed response
Section titled “Change the signed response”Copy the flattened JWS and change one character in its signed payload:
cp authorized-response.jws.json tampered-response.jws.jsonpython3 - <<'PY'import jsonfrom pathlib import Path
path = Path("tampered-response.jws.json")document = json.loads(path.read_text())payload = document["payload"]document["payload"] = ("A" if payload[0] != "A" else "B") + payload[1:]path.write_text(json.dumps(document))PYTry to verify the changed response:
if evidencectl verify tampered-response.jws.json \ --context .evidence/requests/refusal-check/verification.json \ --output tampered-response.verified.jsonthen echo 'unexpected verification success' >&2 exit 1fitest ! -e tampered-response.verified.jsonecho 'TAMPER REFUSED'evidencectl: Evidence Gateway response verification failedTAMPER REFUSEDVerification fails without publishing a trusted payload. Your application must make decisions only from the verifier output, never from an unverified response body.
Clean up
Section titled “Clean up”Stop the local services:
evidencectl dev stopReturn to the registry terminal and press Ctrl+C.
What you proved
Section titled “What you proved”- A valid access token does not widen the provider’s authorized purpose.
- Authorization failure happens before the protected source is called.
- A signed response cannot be changed without invalidating its signature.
- Only verified output is safe for an application to consume.