Auto Sign-out
View SourceAuto 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_everywhereadd-on revokes all tokens for a user (e.g., after a password change) - When tokens are manually revoked via
AshAuthentication.TokenResource.revoke/3
Prerequisites
- Tokens must be enabled in your authentication configuration
- A TokenResource must be configured
- AshAuthentication.Phoenix must be installed (for the notifier and helpers)
- The
log_out_everywhereadd-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:
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
endendpoints- List of Phoenix endpoints to notify when tokens are revokedlive_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:
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
endThe 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:
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
endHow It Works
- When a user signs in,
set_live_socket_id/2stores the live socket ID (generated from the token's JTI) in the session - LiveView uses this socket ID to identify the connection
- When a token is revoked, the
TokenRevocationNotifieruses thelive_socket_id_templatefunction to generate the same socket ID from the revoked token's JTI - The notifier broadcasts a disconnect message through the configured endpoints
- LiveView receives the disconnect and terminates the session
Complete Example
Token Resource
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
endUser Resource with Log Out Everywhere
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.
endAuth Controller
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