# `mix attesto_phoenix.gen.migration`
[🔗](https://github.com/XukuLLC/attesto_phoenix/blob/v0.19.0/lib/mix/tasks/attesto_phoenix.gen.migration.ex#L1)

Generates an Ecto migration that creates the persistence backing the
Ecto-based stores ship with `attesto_phoenix`.

The migration creates nine tables, named to match the runtime schemas
exactly so a by-the-docs deploy installs tables the Ecto-backed stores can
use without modification:

  * `attesto_authorization_codes` - the authorization code grant store
    (`AttestoPhoenix.Schema.Authorization`). Holds one row per issued
    authorization code (RFC 6749, section 4.1) plus the PKCE binding
    (RFC 7636), the optional `cnf` key binding (RFC 7800), the OIDC `nonce`,
    mapped `claims`, the descendant `family_id`, consumed markers, and the
    access-token `jti` issued from a successful redemption so code reuse can
    revoke it. Keyed on `code_hash` (no surrogate id); consulted exactly once
    at the token endpoint.

  * `attesto_refresh_tokens` - the refresh token store
    (`AttestoPhoenix.Schema.RefreshToken`, RFC 6749, section 6). Each row
    carries the rotation `family_id` and `generation` it belongs to, the
    `consumed`/`consumed_at` idempotency markers, `successor` retry payload,
    `family_revoked` sticky revocation flag, the `cnf` key binding, mapped
    `claims`, and the diagnostic `parent_hash`, so that reuse of a rotated
    token can be detected and the whole family revoked (RFC 6819, section
    5.2.2.3 - refresh token rotation / replay detection).

  * `attesto_device_codes` - the device authorization grant store
    (`AttestoPhoenix.Schema.DeviceCode`, RFC 8628). One row per device code,
    keyed on `device_code_hash` (the poll key) and `user_code` (the
    verification key), carrying the bound `scope`/`resource`/`dpop_jkt`, the
    `status` state machine (pending → approved|denied → consumed), the
    approved `subject`/`granted_scope`/`granted_claims`, and `last_polled_at`
    for the section 3.5 poll-interval guard.

  * `attesto_logout_sessions` - the Back-Channel Logout session store
    (`AttestoPhoenix.Schema.LogoutSession`, OpenID Connect Back-Channel Logout
    1.0). One row per `(session, Relying Party)` pair, recorded at ID-Token
    mint and read at the end-session endpoint to deliver a `logout_token`.
    Upserted on `(sid, client_id)`; carries the `subject`, the RP's
    `backchannel_logout_uri`/`session_required`, and the `expires_at` that
    bounds an abandoned session.

  * `dpop_nonces` - server-issued DPoP nonces
    (`AttestoPhoenix.Schema.DPoPNonce`, RFC 9449, section 8). Each row is a
    single-use nonce carrying `issued_at`, `expires_at`, and the `used_at`
    consumption marker.

  * `dpop_replays` - the DPoP proof replay cache keyed by the proof's `jti`
    as its PRIMARY KEY (`AttestoPhoenix.Schema.DPoPReplay`, RFC 9449,
    section 11.1). A row is the record that a given proof JWT has already been
    seen within its acceptance window.

  * `attesto_pushed_authorization_requests` - the Pushed Authorization Request
    store (`AttestoPhoenix.Schema.PushedAuthorizationRequest`, RFC 9126). Each
    row maps a one-time `request_uri` reference (the PRIMARY KEY) to the stored,
    validated authorization request `params` and the reference `expires_at`, so
    a `request_uri` pushed to one node is resolvable on every node (FAPI 2.0
    requires PAR).

  * `attesto_client_id_metadata` - the Client ID Metadata Document cache
    (`AttestoPhoenix.Schema.ClientIdMetadata`,
    `draft-ietf-oauth-client-id-metadata-document-01`). Each row caches one
    *validated* CIMD document under its `client_id` URL (the PRIMARY KEY), as a
    jsonb `metadata` map plus the `expires_at` derived from the response's HTTP
    freshness directives (RFC 9111). Keeps every authorization request from
    re-fetching the URL and, being shared, makes the cache coherent across a
    cluster and bounds the outbound fetch fan-out.

  * `attesto_consent_grants` - the single-use, request-bound consent grant
    store (`AttestoPhoenix.Schema.ConsentGrant` / `EctoConsentGrantStore`,
    RFC 6749 §4.1.1). Each row records one consent decision keyed on an
    unguessable `token` (the PRIMARY KEY), with a `binding_hash` over the exact
    request the user saw and a short `expires_at`; `consumed_at` marks single
    use. The host consent screen mints a row; the host's `:consent` callback
    consumes it before a code is issued, so one consent click cannot approve a
    different client/redirect/scope/challenge.

## Usage

    mix attesto_phoenix.gen.migration --repo MyApp.Repo

## Options

  * `--repo` - the Ecto repo module the migration is generated for. May be
    given more than once to target several repos. When omitted the repos
    configured for the host application are used (the same resolution
    `mix ecto.gen.migration` performs).

  * `--table-prefix` - an optional prefix applied to every generated table
    name (for example `--table-prefix oauth_` yields
    `oauth_attesto_authorization_codes`).
    Defaults to no prefix. When omitted, the prefix configured for the host
    (`:table_prefix` on the `AttestoPhoenix.Config` keyword the host puts in
    its application environment) is used so the generated tables match the
    prefix the Ecto stores read at runtime; the task never invents a prefix.

  * `--migrations-path` - directory the migration file is written to. Defaults
    to the repo's `priv/<repo>/migrations` directory, the same location
    `mix ecto.gen.migration` uses.

  * `--otp-app` - the host application whose environment holds the
    `AttestoPhoenix.Config` keyword to read `:table_prefix` from when
    `--table-prefix` is omitted. Optional; without it the default (no prefix)
    is used.

  * `--config-key` - the application environment key the host stores its
    `AttestoPhoenix.Config` keyword under. Defaults to `AttestoPhoenix.Config`,
    matching `AttestoPhoenix.Config.from_otp_app/2`. Only consulted together
    with `--otp-app`.

The generated migration is reversible: `up` creates the tables and indexes and
`down` drops them.

---

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