The native backend's sessions (ported from exio's Accounts.Sessions),
in macaw_auth_sessions (Macaw.Auth.Native.SessionRecord).
- Only a hash is stored. A session's token is 32 random bytes; the client holds it and the table holds its SHA-256. The token is never written, so reading the table (a backup, a leaked dump) signs nobody in, and since the token is uniformly random, a plain unsalted hash is as strong as the token: there is nothing to guess.
- Idle expiry slides. A session unused for
session_idle_days(Macaw.Auth.Native.Config, default 14) expires and is deleted at its next look-up. A request (touch: true) records use, but writeslast_used_atat most once an hour: a write per request would make every page view a database write, which SQLite's single writer feels. A re-check (touch: false, an open page's periodic look) never extends a session, or an idle browser tab would keep it alive forever. - A disabled user has no session. Looking one up deletes it and refuses it, so disabling a user takes effect at their next request, and their open pages leave at their next re-check.
- Revocation only deletes.
revoke/2returns{user_id, ids}; the push to open pages is the facade's (Macaw.Auth.revoke/2), the same for every backend.
Every function honors :now (a DateTime). Telemetry
[:macaw_auth, :native, :session]: %{count: n} with %{event: :created | :expired | :revoked, reason: atom | nil, user_id: id};
never a token or its hash.
Summary
Functions
Records a completed step: :second_factor and :second_factor_enroll
mark the second factor passed; any other step joins completed_steps.
A session that doesn't exist, or was deleted meanwhile (a revocation
racing the step), is left gone and refused: {:error, :invalid}.
Starts a session for user: {:ok, token, session}, the token for the
client only, or {:error, :invalid} when the user no longer exists
(deleted since signing in). Options: :remote_ip (a string or an
address tuple), :user_agent, :second_factor_passed (default true),
:now.
Resolves a token: {:ok, user, session} or {:error, :invalid | :expired | :disabled}. Options: :touch (default false), :now.
As fetch/2, by session id: what an open page re-checks with.
The SHA-256 of a token: what the table stores.
A user's sessions, newest first (created at, then id: timestamps can tie).
Deletes one session (an id) or a user's ({:user, id}, keeping
:except): {user_id, ids}, the ids empty when nothing was there.
:reason goes to telemetry.
Deletes every session of user user_id's, reason going to telemetry,
and tells their open pages (Macaw.Auth.announce_revoked/2), which
disconnect, unless option announce: false: a process that is not the
app's node (a release's eval, a mix task) has no page to tell, and the
pages leave at their next re-check. What an administrator's change of a
user (Macaw.Auth.Native.set_password/3, admin_reset/2) revokes with.
A row as the contract's %Macaw.Auth.Session{}.
Functions
@spec complete_step(term(), Macaw.Auth.step(), keyword()) :: :ok | {:error, :invalid}
Records a completed step: :second_factor and :second_factor_enroll
mark the second factor passed; any other step joins completed_steps.
A session that doesn't exist, or was deleted meanwhile (a revocation
racing the step), is left gone and refused: {:error, :invalid}.
@spec create(Macaw.Auth.User.t(), keyword()) :: {:ok, binary(), Macaw.Auth.Session.t()} | {:error, :invalid}
Starts a session for user: {:ok, token, session}, the token for the
client only, or {:error, :invalid} when the user no longer exists
(deleted since signing in). Options: :remote_ip (a string or an
address tuple), :user_agent, :second_factor_passed (default true),
:now.
@spec fetch(binary(), keyword()) :: {:ok, Macaw.Auth.User.t(), Macaw.Auth.Session.t()} | {:error, :invalid | :expired | :disabled}
Resolves a token: {:ok, user, session} or {:error, :invalid | :expired | :disabled}. Options: :touch (default false), :now.
@spec fetch_by_id(term(), keyword()) :: {:ok, Macaw.Auth.User.t(), Macaw.Auth.Session.t()} | {:error, :invalid | :expired | :disabled}
As fetch/2, by session id: what an open page re-checks with.
The SHA-256 of a token: what the table stores.
@spec list(term(), keyword()) :: [Macaw.Auth.Session.t()]
A user's sessions, newest first (created at, then id: timestamps can tie).
Deletes one session (an id) or a user's ({:user, id}, keeping
:except): {user_id, ids}, the ids empty when nothing was there.
:reason goes to telemetry.
Deletes every session of user user_id's, reason going to telemetry,
and tells their open pages (Macaw.Auth.announce_revoked/2), which
disconnect, unless option announce: false: a process that is not the
app's node (a release's eval, a mix task) has no page to tell, and the
pages leave at their next re-check. What an administrator's change of a
user (Macaw.Auth.Native.set_password/3, admin_reset/2) revokes with.
@spec to_session(Macaw.Auth.Native.SessionRecord.t()) :: Macaw.Auth.Session.t()
A row as the contract's %Macaw.Auth.Session{}.