# `Macaw.Auth.Native.Sessions`
[🔗](https://github.com/dcoai/macaw_auth/blob/v0.4.1/lib/macaw/auth/native/sessions.ex#L1)

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 writes
  `last_used_at` at 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/2` returns `{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.

# `complete_step`

```elixir
@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}`.

# `create`

```elixir
@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`.

# `fetch`

```elixir
@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`.

# `fetch_by_id`

```elixir
@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.

# `hash`

```elixir
@spec hash(binary()) :: binary()
```

The SHA-256 of a token: what the table stores.

# `list`

```elixir
@spec list(term(), keyword()) :: [Macaw.Auth.Session.t()]
```

A user's sessions, newest first (created at, then id: timestamps can tie).

# `revoke`

```elixir
@spec revoke(term() | {:user, term()}, keyword()) :: {term(), [term()]}
```

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.

# `revoke_all`

```elixir
@spec revoke_all(term(), atom(), keyword()) :: :ok
```

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.

# `to_session`

```elixir
@spec to_session(Macaw.Auth.Native.SessionRecord.t()) :: Macaw.Auth.Session.t()
```

A row as the contract's `%Macaw.Auth.Session{}`.

---

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