AshAuthentication.Strategy.RememberMe (ash_authentication v4.13.3)
View SourceStrategy for authenticating using a remember me token that has a configurable token_lifetime and is typically valid longer than a session token. Remember me tokens are generated by other strategies (e.g. MagicLink) to allow for authentication to continue beyond the scope of the current session.
In order to use remember me authentication you need to have another strategy enabled that supports remember me.
Example Usage
Add the Remember Me strategy to your authenticated resource and update another strategy to the generate the remember_me token.
defmodule MyApp.Accounts.User do
use Ash.Resource,
extensions: [AshAuthentication],
domain: MyApp.Accounts
attributes do
uuid_primary_key :id
attribute :email, :ci_string, allow_nil?: false
end
authentication do
# Tokens are required for RememberMe
tokens do
enabled? true
store_all_tokens? true
require_token_presence_for_authentication? true
end
# Make sure you use the log_out_everywhere add on
# to revoke remember me tokens on password change otherwise
# the remember me tokens will continue to sign in users
add_ons do
log_out_everywhere do
apply_on_password_change? true
end
end
strategies do
password do
identity_field :email
hashed_password_field :hashed_password
hash_provider AshAuthentication.BcryptProvider
confirmation_required? true
end
# Add the remember me Strategy
remember_me :remember_me do
sign_in_action_name :sign_in_with_remember_me # Optional defaults to :sign_in_with_[:strategy_name]
cookie_name :remember_me # Optional. Defaults to :remember_me
token_lifetime {30, :days} # Optional. Defaults to {30, :days}
end
end
end
# In any of the actions used by your other strategies...
actions do
read :sign_in_with_password do
...
# Add an argument to your form
argument :remember_me, :boolean do
description "Whether to generate a remember me token."
allow_nil? true
end
# Add the preparation that generates the token
prepare {AshAuthentication.Strategy.RememberMe.MaybeGenerateTokenPreparation, strategy_name: :remember_me}
# Add the metadata map that will contain the cookie_name, token, and other values
# after a successful sign in.
metadata :remember_me, :map do
description "A map that includes the token options"
allow_nil? true
end
end
read :sign_in_with_remember_me do
description "Attempt to sign in using a remember me token."
get? true
argument :token, :string do
description "The remember me token"
allow_nil? false
sensitive? true
end
# validates the provided the remember me token and generates a token for the session
prepare AshAuthentication.Strategy.RememberMe.SignInPreparation
metadata :token, :string do
description "A JWT that can be used to authenticate the user."
allow_nil? false
end
end
end
endWhen the user successfully signs in, the user.metadata.remember_me field will contain a map with the token and max_age.
For create actions, such as registering a new user and signing them in immediately,
use AshAuthentication.Strategy.RememberMe.MaybeGenerateTokenChange. This serves as
an alternative to the preparation used for read actions and mirrors the behavior of the Magic Link strategy.
If you're using AshAuthentication.Phoenix, update your AuthController to store the cookie with
a put_remember_me_cookie/3 callback. Other callbacks include delete_remember_me_cookie/2,
and delete_all_remember_me_cookies/1
defmodule MyAppWeb.AuthController do
use MyAppWeb, :controller
use AshAuthentication.Phoenix.Controller
@impl AshAuthentication.Phoenix.Controller
def put_remember_me_cookie(conn, cookie_name, %{token: token, max_age: max_age}) do
cookie_options = [
max_age: max_age, # matches the token lifetime
http_only: true, # prevents the cookie from being accessed by JavaScript
secure: true, # only send the cookie over HTTPS
same_site: "lax" # prevents the cookie from being sent with cross-site requests
]
conn
|> put_resp_cookie(cookie_name, token, cookie_options)
end
endUpdate your router to sign in the user with the remember me token.
defmodule MyAppWeb.Router do
pipeline :browser do
...
plug :sign_in_with_remember_me # make sure this comes before load_from_session
plug :load_from_session
end
endYou should also delete the remember me token on sign out to prevent the user from immediately being signed back in. This will sign them out of their current session, but it will not revoke remember me tokens on other devices.
defmodule MyAppWeb.AuthController do
use MyAppWeb, :controller
use AshAuthentication.Phoenix.Controller
@impl AshAuthentication.Phoenix.Controller
def sign_out(conn, _params) do
return_to = get_session(conn, :return_to) || ~p"/"
conn
|> clear_session(:my_otp_app)
|> AshAuthentication.Strategy.RememberMe.Plug.Helpers.delete_all_remember_me_cookies(:my_otp_app)
|> put_flash(:info, "You are now signed out")
|> redirect(to: return_to)
end
end
Summary
Functions
Callback implementation for AshAuthentication.Strategy.Custom.transform/2.
Callback implementation for AshAuthentication.Strategy.Custom.verify/2.
Types
@type t() :: %AshAuthentication.Strategy.RememberMe{ __spark_metadata__: Spark.Dsl.Entity.spark_meta(), cookie_name: atom(), identity_field: atom(), name: atom(), registration_enabled?: boolean(), resource: module(), sign_in_action_name: :atom, token_lifetime: pos_integer() }
Functions
Callback implementation for AshAuthentication.Strategy.Custom.transform/2.
Callback implementation for AshAuthentication.Strategy.Custom.verify/2.