# `PhoenixKit.Users.LoginAlerts`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v1.7.213/lib/phoenix_kit/users/login_alerts.ex#L1)

New-login security alerts ("we noticed a new login to your account").

On every login (`PhoenixKitWeb.Users.Auth.log_in_user/3`), the request's
`(ip_address, user_agent_hash)` pair is checked against
`PhoenixKit.Users.Auth.KnownDevice` rows for that user. An unrecognized
pair is a new device: it's persisted, a `user.new_login_detected`
activity entry is logged, and — when `new_login_alert_enabled` is on —
an email goes out via
`PhoenixKit.Users.Auth.UserNotifier.deliver_new_login_alert/2`.

A recognized pair just bumps `last_seen_at` — no alert, no email.

Sends synchronously (matching every other PhoenixKit auth email —
confirmation, password reset, magic link — none of which are queued
through Oban): a "new device" login is inherently rare per user (every
subsequent login from the same device is silent), so the odd extra
round-trip on a first-time login doesn't justify background-job
infrastructure this feature would otherwise be the only user of. A
send failure is logged and swallowed — it must never block sign-in.

# `check`

```elixir
@spec check(map(), Plug.Conn.t()) :: :ok
```

Records a login from `conn` for `user`, alerting on a new device.

No-ops entirely (no DB write, no email) when the feature is disabled.
Never raises — a failure here must never block sign-in.

# `enabled?`

```elixir
@spec enabled?() :: boolean()
```

Whether new-login alerts are enabled (setting `new_login_alert_enabled`,
default `false`).

# `location_for`

```elixir
@spec location_for(String.t()) :: String.t() | nil
```

Best-effort "City, Country" string for `ip_address`, or `nil`.

Never raises; a lookup failure (disabled, rate-limited, invalid IP)
just means the alert email omits the location line.

---

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