class

KemalIdentity::SQLite::AccountRepository

Inherits KemalIdentity::Accounts::Repository < Reference < Object

Accounts::Repository over the reference auth_accounts table, SQLite dialect.

Same contract, same reference-implementation caveat as the PostgreSQL adapter: an application with its own users table implements the contract over that and never creates auth_accounts at all.

Constants

COLUMNS = "id, tenant_id, normalized_login, email_verified_at, disabled_at,\nauth_version, password_digest, password_scheme, created_at, updated_at"

Constructors

Instance methods

bump_auth_version(id : String) : Int32 | Nil

Increments auth_version and returns the new value, or nil if no such account exists.

Invalidates every session for the account without enumerating rows: each session stores the auth_version it was minted under, and a mismatch fails the session on its next read. Used on password change and MFA recovery, alongside explicit revocation rather than instead of it (docs/02-security-model.md).

Also the answer for a change to the account's tenant, which is the one authorization input a session copies: without a bump or an explicit revocation, sessions that already exist keep the tenant they were minted with until they expire (Sessions::Record#tenant_id).

Source
find_by_id(id : String) : Accounts::Account | Nil

The account with this id, or nil.

Source
find_by_login(normalized_login : String, tenant_id : String | Nil = nil) : Accounts::Account | Nil

The null-tenant case is split out for the same reason as in PostgreSQL: tenant_id = NULL is unknown rather than false in SQLite too, so the obvious parameterised query returns no rows for every single-tenant application.

Source
mark_email_verified(id : String, at : Time) : Bool

Records that this account's address has been proved, and returns false if no such account exists.

Idempotent: confirming twice is not an error, and the second call moves the timestamp forward rather than refusing. A user who clicks a link twice has not done anything wrong.

Source
update_password_digest(id : String, digest : String, scheme : String, at : Time) : Bool

Replaces the stored digest and scheme, and moves updated_at to at.

This is the lazy-rehash write: a successful login against a digest at an outdated cost rehashes at the current one, so old digests disappear as people sign in and nobody is forced through a password reset (docs/06-roadmap.md).

Returns false if no such account exists. Does not revoke sessions — a rehash of the same password is not a credential change, and revoking here would log everyone out of the application that just upgraded its cost.

Source