Ithibati.Identity.RecoveryCodes (Ithibati v0.2.0)

Copy Markdown View Source

Issues and redeems single-use recovery codes for accounts without an available passkey.

A batch contains twelve codes by default. Issuance returns plaintext codes while storage keeps only their SHA-256 digests. The application must display or deliver the plaintext at issuance.

Spending the last unused code refills the batch by default. Redemption returns the account and any fresh codes; the caller decides whether to issue a session.

Summary

Functions

Spends a recovery code and returns {:ok, account, fresh_codes} or {:error, :invalid}.

Returns a fresh list of plaintext codes and invalidates all previous codes for the account.

How many unused codes this account has left.

Functions

redeem(code, opts \\ [])

Spends a recovery code and returns {:ok, account, fresh_codes} or {:error, :invalid}.

fresh_codes is nil while unused codes remain. When the last one is spent, the same transaction issues a replacement batch and returns its plaintext list. Preserve that list for display; it cannot be recovered from the stored digests.

Options

  • :refill — defaults to true; pass false to disable replacement.
  • :count — size of a replacement batch, default 12. Accepts a non-negative integer; invalid values raise when a replacement batch is needed.

Unknown and already-spent codes both return {:error, :invalid}. A nil input returns the same error; other non-string inputs do not match the function's clauses.

Redemption does not create a session. Concurrent redemption and regeneration are serialized on the account row so spending and refilling use a consistent ordering.

regenerate(account, opts \\ [])

Returns a fresh list of plaintext codes and invalidates all previous codes for the account.

The :count option defaults to 12 and accepts a non-negative integer. count: 0 invalidates the previous batch without issuing replacements. Other values raise ArgumentError.

The account must belong to the configured schema and exist in the database. Replacement is transactional and serialized with other regeneration and redemption calls for that account.

Only digests are stored. Display or deliver the returned codes now; they cannot be retrieved from the database later.

remaining(account)

How many unused codes this account has left.