Attesto.PresentationSessionStore behaviour (Attesto v1.9.0)

Copy Markdown View Source

Storage seam for verifier-side OID4VP presentation sessions.

A session starts pending and may transition to completed exactly once. complete/2 is security-critical: implementations MUST atomically guard the update on the current pending status and on the session being unexpired. Two concurrent wallet responses for one session therefore cannot both win or overwrite one another. A SQL implementation would use one conditional UPDATE ... WHERE status = 'pending' AND expires_at > now; the reference ETS implementation serializes this transition through its owner process.

The optional take/1 callback lets a host atomically poll and clear a completed result. get/1 is non-consuming and is suitable for serving a request URI or polling without clearing the result.

Summary

Callbacks

Atomically attach the signed request object to an unexpired pending session.

Atomically attach the verifier's per-request (ephemeral) response-encryption private JWK to an unexpired pending session, for direct_post.jwt decryption.

Atomically transition an unexpired pending session to completed.

Read a presentation session without consuming it.

Persist a new pending presentation session.

Atomically fetch and clear an unexpired completed session.

Types

entry()

@type entry() :: %{id: String.t(), data: map(), expires_at: integer()}

Callbacks

attach_request_object(id, request_object)

(optional)
@callback attach_request_object(id :: String.t(), request_object :: String.t()) ::
  :ok | :error

Atomically attach the signed request object to an unexpired pending session.

Called once at creation time (before the session id is published), so it guards on pending like complete/2. Returns :error when the session is unknown, expired, or no longer pending.

attach_response_encryption_jwk(id, jwk)

(optional)
@callback attach_response_encryption_jwk(id :: String.t(), jwk :: map()) :: :ok | :error

Atomically attach the verifier's per-request (ephemeral) response-encryption private JWK to an unexpired pending session, for direct_post.jwt decryption.

complete(id, result)

@callback complete(id :: String.t(), result :: map()) :: :ok | :error

Atomically transition an unexpired pending session to completed.

The supplied result is retained with the session. Returns :error when the session is unknown, expired, or no longer pending.

get(id)

@callback get(id :: String.t()) :: {:ok, entry()} | :error

Read a presentation session without consuming it.

put(entry)

@callback put(entry()) :: :ok

Persist a new pending presentation session.

take(id)

(optional)
@callback take(id :: String.t()) :: {:ok, entry()} | :error

Atomically fetch and clear an unexpired completed session.