AttestoClient

Hex.pmHexdocs.pmLicense: MITOpenID Certified

OpenID Certified

AttestoClient is OpenID Certified as a Relying Party library to the Basic, Config, and Dynamic OP profiles, run against the OpenID Foundation's conformance suite.

Run a secure OpenID Connect Authorization Code + PKCE exchange, refresh and revoke tokens, build RP-Initiated Logout requests, and build or verify the OAuth and OpenID Connect wire artifacts an Elixir client needs: private_key_jwt, signed authorization request objects (JAR), strict ID Token verification, JARM, ID-JAG/EMA assertions, signed introspection and UserInfo, and discovery/JWKS.

Use it when you are writing a relying party or OAuth client that needs secure protocol mechanics without delegating application policy:

AttestoClient is the client-side counterpart to attesto. attesto verifies client artifacts and issues server artifacts with the authorization server's keystore; AttestoClient builds artifacts signed with the client's own key and verifies the server artifacts a client receives.

On the server side of the same family, attesto_phoenix is the batteries-included Phoenix/Ecto authorization server built on attesto, and attesto_mcp protects a Model Context Protocol server as an OAuth resource server.

It does not make authorization decisions or own application sessions. Its included ETS store retains only short-lived protocol correlation data, and its refresh coordinator retains no token set after a flight completes. The host chooses its durable/distributed store, atomically persists rotation results, maps verified identities to authorization, and applies session-retention policy. DPoP proof generation for outgoing requests is req_dpop's job.

What it provides

Example

key = JOSE.JWK.generate_key({:ec, "P-256"})
{:ok, assertion} =
AttestoClient.ClientAssertion.build(key,
client_id: "my-client",
audience: "https://op.example.com"
)
# Submit it at the token / PAR / introspection endpoint:
# client_assertion_type = AttestoClient.ClientAssertion.assertion_type()
# client_assertion = assertion

For a full authorization flow, store setup, callback handling, refresh, revocation, and logout, see the Authorization Code guide.

For inbound JWT access-token verification backed by a remote issuer, including key rotation, stale-key behavior, scope checks, and Plug wiring, see the Remote issuer resource-server guide.

Assurance

Build-side artifacts carry cross-language parity tests where practical: they are checked against an independent, non-Elixir reference implementation (e.g. PyJWT), so correctness does not rest only on this library and attesto agreeing with each other. The mirror modules also carry in-family interop tests against the corresponding attesto server-side issuer or verifier. The Python parity tests skip cleanly when the reference toolchain is absent, so they never block a plain mix test.

For release confidence, run them explicitly against a Python with the reference libraries installed (the system Python is usually PEP-668 externally managed, so use a venv):

python3 -m venv .venv
.venv/bin/pip install "pyjwt[crypto]"
ATTESTO_CLIENT_PYTHON=.venv/bin/python ATTESTO_PATH=1 mix test

When ATTESTO_CLIENT_PYTHON is unset the harness falls back to python3 on the PATH.

Status

A stable 2.x release: the public API follows semantic versioning — minor and patch releases are backward-compatible, and breaking changes wait for a new major version. Pin to ~> 2.0.

Requirements

AttestoClient requires Elixir 1.18 or later. Both this package and its required attesto dependency use Elixir's built-in JSON module, so lowering only this package's declared floor would not create a working older-Elixir installation.