Signing in and staying signed in: session and magic-link tokens, the emails that carry them, and listing or revoking a user's sessions.
Split out of Gamend.Accounts, which still exposes every function here under
the same name. Revoking every token on a credential change stays there, next
to the writes that trigger it.
Summary
Functions
Counts tokens for a given user.
Deletes the signed token with the given context.
Delivers the magic link login instructions to the given user.
Delivers the update email instructions to the given user.
Generates a session token.
Gets the user with the given magic link token.
Gets the user with the given signed token.
Lists tokens for a given user, optionally filtered by context.
Logs the user in by magic link.
Revokes all session tokens for a user (mass logout).
Functions
@spec count_user_tokens(Ecto.UUID.t()) :: non_neg_integer()
Counts tokens for a given user.
@spec delete_user_session_token(binary()) :: :ok
Deletes the signed token with the given context.
@spec deliver_login_instructions(Gamend.Accounts.User.t(), (String.t() -> String.t())) :: {:ok, Swoosh.Email.t()} | {:error, term()}
Delivers the magic link login instructions to the given user.
@spec deliver_user_update_email_instructions( Gamend.Accounts.User.t(), String.t(), (String.t() -> String.t()) ) :: {:ok, Swoosh.Email.t()} | {:error, term()}
Delivers the update email instructions to the given user.
Examples
iex> deliver_user_update_email_instructions(user, current_email, &url(~p"/users/settings/confirm_email/#{&1}"))
{:ok, %{to: ..., body: ...}}
@spec generate_user_session_token(Gamend.Accounts.User.t()) :: binary()
Generates a session token.
@spec get_user_by_magic_link_token(String.t()) :: Gamend.Accounts.User.t() | nil
Gets the user with the given magic link token.
@spec get_user_by_session_token(binary()) :: {Gamend.Accounts.User.t(), DateTime.t()} | nil
Gets the user with the given signed token.
If the token is valid {user, token_inserted_at} is returned, otherwise nil is returned.
@spec list_user_tokens(Ecto.UUID.t(), keyword()) :: [Gamend.Accounts.UserToken.t()]
Lists tokens for a given user, optionally filtered by context.
@spec login_user_by_magic_link(String.t()) :: {:ok, {Gamend.Accounts.User.t(), [Gamend.Accounts.UserToken.t()]}} | {:error, :not_found | Ecto.Changeset.t() | term()}
Logs the user in by magic link.
There are three cases to consider:
The user has already confirmed their email. They are logged in and the magic link is expired.
The user has not confirmed their email. Opening the link proves they own the inbox, so the user gets confirmed, logged in, and all tokens - including session ones - are expired.
As 2, with a password set: registered when
POST /api/v1/registerstill took one, or a guest account given an email, and never confirmed. The password is removed as the email is confirmed. Whoever set it did so before anyone proved they own the inbox, so it may be someone else's, and kept it would sign them into the account its owner has just claimed (the "Mixing magic link and password registration" section ofmix help phx.gen.auth). The owner sets a new one in settings. The confirmation email's link removes it the same way (Gamend.Accounts.confirm_user_by_token/1); its code sets the password.
@spec revoke_all_user_sessions(Ecto.UUID.t()) :: {non_neg_integer(), nil}
Revokes all session tokens for a user (mass logout).