Packages
ash_authentication
5.0.0-rc.6
5.0.0-rc.12
5.0.0-rc.11
5.0.0-rc.10
5.0.0-rc.9
5.0.0-rc.8
5.0.0-rc.7
5.0.0-rc.6
5.0.0-rc.5
5.0.0-rc.4
5.0.0-rc.3
5.0.0-rc.2
5.0.0-rc.1
5.0.0-rc.0
4.14.1
4.14.0
4.13.7
4.13.6
4.13.5
4.13.4
4.13.3
4.13.2
retired
4.13.1
retired
4.13.0
4.12.0
4.11.0
4.10.0
4.9.9
4.9.8
4.9.7
4.9.6
4.9.5
4.9.4
4.9.3
4.9.2
4.9.1
4.9.0
4.8.7
4.8.6
4.8.5
4.8.3
4.8.2
4.8.1
4.8.0
4.7.6
4.7.5
4.7.4
4.7.3
4.7.2
4.7.1
4.7.0
4.6.4
4.6.3
4.6.2
4.6.1
4.6.0
4.5.6
4.5.5
4.5.4
4.5.3
4.5.2
4.5.1
4.5.0
4.4.9
4.4.8
4.4.7
4.4.6
4.4.5
4.4.4
4.4.3
4.4.2
4.4.1
4.4.0
4.3.12
4.3.11
4.3.10
4.3.9
4.3.8
4.3.7
4.3.6
4.3.5
4.3.4
4.3.3
4.3.2
4.3.1
4.3.0
4.2.7
4.2.6
4.2.5
4.2.4
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.4
4.0.3
4.0.2
4.0.1
4.0.0
4.0.0-rc.6
4.0.0-rc.5
4.0.0-rc.3
4.0.0-rc.2
4.0.0-rc.1
4.0.0-rc.0
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.16
3.11.15
3.11.14
3.11.13
3.11.12
3.11.11
3.11.10
3.11.9
3.11.8
3.11.7
3.11.6
3.11.5
3.11.4
3.11.3
3.11.2
3.11.1
3.11.0
3.10.8
3.10.7
3.10.6
3.10.5
3.10.4
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.0
3.7.9
3.7.8
3.7.6
3.7.5
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
3.6.1
3.6.0
3.5.3
3.5.2
3.5.1
3.5.0
3.3.1
3.3.0
3.2.2
3.2.1
3.2.0
3.1.0
3.0.3
Authentication extension for the Ash Framework.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
documentation/topics/auto-signout.md
<!--
SPDX-FileCopyrightText: 2022 Alembic Pty Ltd
SPDX-License-Identifier: MIT
-->
# Auto Sign-out
Auto sign-out automatically disconnects LiveView sessions when a user's tokens are revoked. This ensures that when a user signs out (or triggers "sign out everywhere"), any active LiveView sessions are immediately disconnected rather than remaining active until the next page refresh.
## When Auto Sign-out Triggers
Auto sign-out is triggered whenever tokens are revoked, which happens:
- When a user explicitly signs out
- When the `log_out_everywhere` add-on revokes all tokens for a user (e.g., after a password change)
- When tokens are manually revoked via `AshAuthentication.TokenResource.revoke/3`
## Prerequisites
1. **Tokens must be enabled** in your authentication configuration
2. **A TokenResource** must be configured
3. **AshAuthentication.Phoenix** must be installed (for the notifier and helpers)
4. The `log_out_everywhere` add-on is recommended for password change scenarios
## Configuration
### Step 1: Configure TokenResource (AshAuthentication)
Add the `endpoints` and `live_socket_id_template` options to your token resource:
```elixir
defmodule MyApp.Accounts.Token do
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication.TokenResource],
domain: MyApp.Accounts
postgres do
table "tokens"
repo MyApp.Repo
end
token do
endpoints [MyAppWeb.Endpoint]
live_socket_id_template fn %{jti: jti} -> "users_sessions:#{jti}" end
end
end
```
- `endpoints` - List of Phoenix endpoints to notify when tokens are revoked
- `live_socket_id_template` - Function that generates the live socket ID from a map containing `%{jti: jti}`. Additional keys may be added in future versions.
### Step 2: Add the Notifier (AshAuthentication.Phoenix)
Add `AshAuthentication.Phoenix.TokenRevocationNotifier` to your token resource's notifiers:
```elixir
defmodule MyApp.Accounts.Token do
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication.TokenResource],
domain: MyApp.Accounts,
notifiers: [AshAuthentication.Phoenix.TokenRevocationNotifier]
# ... rest of configuration
end
```
The notifier broadcasts disconnect messages through your configured endpoints when tokens are revoked.
### Step 3: Set Live Socket ID on Sign-in (AshAuthentication.Phoenix)
In your authentication controller, call `set_live_socket_id/2` after successful sign-in to store the socket ID in the session:
```elixir
defmodule MyAppWeb.AuthController do
use MyAppWeb, :controller
use AshAuthentication.Phoenix.Controller
def success(conn, _activity, user, _token) do
conn
|> set_live_socket_id(user)
|> store_in_session(user)
|> assign(:current_user, user)
|> redirect(to: ~p"/")
end
def failure(conn, _activity, _reason) do
conn
|> put_flash(:error, "Authentication failed")
|> redirect(to: ~p"/sign-in")
end
def sign_out(conn, _params) do
conn
|> clear_session()
|> redirect(to: ~p"/")
end
end
```
## How It Works
1. When a user signs in, `set_live_socket_id/2` stores the live socket ID (generated from the token's JTI) in the session
2. LiveView uses this socket ID to identify the connection
3. When a token is revoked, the `TokenRevocationNotifier` uses the `live_socket_id_template` function to generate the same socket ID from the revoked token's JTI
4. The notifier broadcasts a disconnect message through the configured endpoints
5. LiveView receives the disconnect and terminates the session
## Complete Example
### Token Resource
```elixir
defmodule MyApp.Accounts.Token do
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication.TokenResource],
domain: MyApp.Accounts,
notifiers: [AshAuthentication.Phoenix.TokenRevocationNotifier]
postgres do
table "tokens"
repo MyApp.Repo
end
token do
endpoints [MyAppWeb.Endpoint]
live_socket_id_template fn %{jti: jti} -> "users_sessions:#{jti}" end
end
end
```
### User Resource with Log Out Everywhere
```elixir
defmodule MyApp.Accounts.User do
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication],
domain: MyApp.Accounts
authentication do
tokens do
enabled? true
token_resource MyApp.Accounts.Token
store_all_tokens? true
end
strategies do
password :password do
identity_field :email
end
end
add_ons do
log_out_everywhere do
apply_on_password_change? true
end
end
end
# ... attributes, identities, etc.
end
```
### Auth Controller
```elixir
defmodule MyAppWeb.AuthController do
use MyAppWeb, :controller
use AshAuthentication.Phoenix.Controller
def success(conn, _activity, user, _token) do
conn
|> set_live_socket_id(user)
|> store_in_session(user)
|> assign(:current_user, user)
|> redirect(to: ~p"/")
end
def failure(conn, _activity, _reason) do
conn
|> put_flash(:error, "Authentication failed")
|> redirect(to: ~p"/sign-in")
end
def sign_out(conn, _params) do
conn
|> clear_session()
|> redirect(to: ~p"/")
end
end
```