defmodule PhoenixApiTemplateWeb.Auth.Guardian do use Guardian, otp_app: :phoenix_api_template alias PhoenixApiTemplate.Accounts def subject_for_token(%{id: id}, _claims) do sub = to_string(id) {:ok, sub} end def subject_for_token(_, _) do {:error, :no_id_provided} end def resource_from_claims(%{"sub" => id}) do case Accounts.get_user!(id) do nil -> {:error, :not_found} resource -> {:ok, resource} end end def resource_from_claims(_claims) do {:error, :no_id_provided} end def authenticate(email, password) do case Accounts.get_user_by_email(email) do nil -> {:error, :unauthorized} user -> case validate_password(password, user.hashed_password) do true -> create_token(user, :access) false -> {:error, :unauthorized} end end end def authenticate(token) do with {:ok, claims} <- decode_and_verify(token), {:ok, user} <- resource_from_claims(claims), {:ok, _old, {new_token, _claims}} <- refresh(token) do {:ok, user, new_token} end end defp validate_password(password, hashed_password) do Bcrypt.verify_pass(password, hashed_password) end defp create_token(user, type) do {:ok, token, _claims} = encode_and_sign(user, %{}, token_options(type)) {:ok, user, token} end defp token_options(type) do case type do :access -> [token_type: "access", ttl: {2, :hour}] :reset -> [token_type: "reset", ttl: {15, :minute}] :admin -> [token_type: "admin", ttl: {90, :day}] end end def after_encode_and_sign(resource, claims, token, _options) do with {:ok, _} <- Guardian.DB.after_encode_and_sign(resource, claims["typ"], claims, token) do {:ok, token} end end def on_verify(claims, token, _options) do with {:ok, _} <- Guardian.DB.on_verify(claims, token) do {:ok, claims} end end def on_revoke(claims, token, _options) do with {:ok, _} <- Guardian.DB.on_revoke(claims, token) do {:ok, claims} end end def on_refresh({old_token, old_claims}, {new_token, new_claims}, _options) do with {:ok, _, _} <- Guardian.DB.on_refresh({old_token, old_claims}, {new_token, new_claims}) do {:ok, {old_token, old_claims}, {new_token, new_claims}} end end end