Configure approval trust
Before an approval session can be opened, register your identity provider in the dashboard (per environment: test and live). The API verifies the signed assertion it receives against these three values and refuses anything else. On the test plane, the quickstart script provisions the same trust on its first run throughPUT /v1/approval-trust. Live has no provisioning endpoint; use the dashboard.
Register the origin only:
https://app.example.com. The return_url you send when creating a session may add a path, for example https://app.example.com/approval-return. Attesso compares scheme, host, and port, and returns the browser to the exact URL you sent. The origin must match the registered value exactly: http://localhost:43117 and http://127.0.0.1:43117 are different origins. Test keys accept loopback HTTP only with an explicit port.
Generate an ES256/P-256 key pair on your own infrastructure and register only its public key:
ec_param_enc:named_curve is not optional. Without it, OpenSSL 3.x writes the curve as explicit parameters, and Go’s crypto/x509 (and some other standard libraries) cannot parse the resulting file at all. The key is still valid; it is just unreadable to a large share of stacks.
Derive the public JWK from that PEM with the same jose tooling used to sign assertions (see below):
kid and reference that same kid in the assertion header.
Approval trust is workspace-wide and per environment: one identity issuer and one return origin, with one or two ES256 public keys for rotation. A second registration with different values is refused with 409 APPROVAL_TRUST_ALREADY_REGISTERED. If you run several agent products, give each its own workspace when they need distinct approval brands or return origins; keys rotate in place, but the issuer and origin do not.
Identity assertion contract
The compact JWS must use:
Attesso accepts only the configured issuer and public JWKs. It never fetches a key URL from the token and never receives your private key.
The passkey is bound to the assertion subject. The first approval for a subject registers a passkey; later approvals by that end user assert the registered credential. Keep
subject_reference stable for a person and distinct between people.
TypeScript
Installjose, load the key from your secret store, and keep the resulting token in server memory only.
Python
InstallPyJWT[crypto] and apply the same fixed algorithm and claims.
Go
Standard library only.ecdsa.SignASN1 would produce DER, so sign the digest and
write the 64-byte R || S form yourself; Attesso rejects a DER signature.
Create and handle the session
Send the assertion with a pre-registered return URL and an unpredictablereturn_state:
return_state is required: 16 to 256 characters from A-Z a-z 0-9 . _ ~ -. Attesso returns it unchanged in the fragment. A new session invalidates any previous open session for the same Mandate.
attesso_state, then retrieve the Mandate with your backend API key. The redirect is not proof of approval; the server-to-server Mandate state is authoritative.
If a session expires, reauthenticate the user and create a new session. Never attempt to recover or reuse the old approval URL.
