# `ExMCP.Authorization.OAuthTransactionStore`
[🔗](https://github.com/azmaveth/ex_mcp/blob/v1.4.0/lib/ex_mcp/authorization/oauth_transaction_store.ex#L1)

Bounded, node-local single-use state for OAuth authorization-code flows.

Transactions move atomically through `pending -> code_ready -> redeemed`.
The store retains only SHA-256 digests of state values and authorization
codes, so neither value appears in the store's retained process state or
crash reports.

The built-in store is intentionally node-local because the loopback callback
flow is owned by one ExMCP client process. Applications implementing a
distributed browser callback should terminate that callback on the same node
or provide their own end-to-end authorization provider.

# `callback_error`

```elixir
@type callback_error() ::
  :state_mismatch
  | :missing_authorization_code
  | :missing_callback_issuer
  | :missing_expected_issuer
  | :authorization_transaction_not_found
  | :authorization_transaction_replayed
  | :oauth_transaction_store_unavailable
  | {:issuer_mismatch, keyword()}
```

# `entry`

```elixir
@type entry() :: %{
  state_digest: binary(),
  issuer: String.t() | nil,
  require_issuer: boolean(),
  redirect_uri: String.t(),
  status: :pending | :consumed | :redeemed | {:code_ready, binary()},
  expires_at: integer()
}
```

# `state`

```elixir
@type state() :: %{
  entries: %{optional(transaction_id()) =&gt; entry()},
  max_entries: pos_integer(),
  ttl_ms: pos_integer()
}
```

# `transaction_id`

```elixir
@type transaction_id() :: String.t()
```

# `abort`

```elixir
@spec abort(
  transaction_id(),
  keyword()
) :: :ok
```

Invalidates a transaction after a failed or abandoned flow.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `redeem_code`

```elixir
@spec redeem_code(transaction_id(), String.t(), String.t(), keyword()) ::
  :ok
  | {:error,
     :authorization_transaction_not_found
     | :authorization_code_not_ready
     | :authorization_code_replayed
     | :authorization_code_mismatch
     | :redirect_uri_mismatch
     | :oauth_transaction_store_unavailable}
```

Atomically marks an authorization code as redeemed with its exact redirect URI.

# `register`

```elixir
@spec register(String.t(), String.t() | nil, String.t(), keyword()) ::
  {:ok, transaction_id()} | {:error, term()}
```

Registers a new authorization transaction using a digest of its random state.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

# `validate_callback`

```elixir
@spec validate_callback(transaction_id(), map(), keyword()) ::
  {:ok, String.t()} | {:error, callback_error()}
```

Atomically validates and consumes one callback for a transaction.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
