Lockspire.Domain.InitialAccessToken
(lockspire v1.0.0)
Copy Markdown
Durable initial access token used to gate POST /register when
Lockspire.Domain.ServerPolicy.registration_policy == :initial_access_token.
Hash-at-rest reuses Lockspire.Security.Policy.hash_token/1 (sha256 lowercase hex).
Plaintext is shown once at mint time only (Phase 28 admin LiveView; out of scope for Phase 25).
Phase 25 ships schema + struct only — Lockspire.Protocol.InitialAccessToken.redeem/1
is Phase 26 (DCR-11). Atomicity for redemption depends on the unique_index([:token_hash])
shipped in Plan 03's lockspire_initial_access_tokens migration.
policy_overrides boundary (T-25-05)
This struct's policy_overrides field carries operator-controlled JSON narrowing the
effective DCR allowlists for any registration that uses this IAT. Phase 25 ships the
field as opaque storage — narrowing-at-mint validation (override ⊆ server allowlist)
is a Phase 28 admin-path concern. The Lockspire.Protocol.DcrPolicy.resolve/3 resolver
(Plan 07) does NOT re-validate widening at resolve time per D-18: if a stale override
carries an out-of-allowlist value (e.g., policy was tightened after IAT mint),
MapSet.intersection/2 naturally drops it — never widens.
Summary
Types
Operator-controlled per-IAT narrowing of the resolver's effective DCR allowlists.
Types
Operator-controlled per-IAT narrowing of the resolver's effective DCR allowlists.
String-keyed map (the resolver's override_for/2 looks up string keys) where each value
is a list of strings (the resolver's intersect_axis/4 only lets list values pass
through; non-list values are treated as "no override"). Known keys mirror the
dcr_allowed_* axes:
- "allowed_scopes"
- "allowed_grant_types"
- "allowed_response_types"
- "allowed_redirect_uri_schemes"
- "allowed_redirect_uri_hosts"
- "allowed_token_endpoint_auth_methods"
Pinning the shape here lets Dialyzer catch drift between admin-mint (Phase 28) and
resolve-time (Phase 25 Lockspire.Protocol.DcrPolicy.resolve/3). A malformed
%{atom_key: "string"} would silently bypass every override under the looser
map() | nil typespec — see DCR-09 and the WR-09 follow-up invariant test (Phase 28).
@type t() :: %Lockspire.Domain.InitialAccessToken{ created_by: String.t() | nil, expires_at: DateTime.t() | nil, id: integer() | nil, inserted_at: DateTime.t() | nil, policy_overrides: policy_overrides() | nil, revoked_at: DateTime.t() | nil, single_use: boolean(), token_hash: String.t() | nil, updated_at: DateTime.t() | nil, used_at: DateTime.t() | nil }