defmodule Guardian.DB.Token do @moduledoc """ A very simple model for storing tokens generated by `Guardian`. """ use Ecto.Schema import Ecto.Changeset alias Guardian.DB.Token @primary_key {:jti, :string, autogenerate: false} @required_fields ~w(jti aud)a @allowed_fields ~w(jti typ aud iss sub exp jwt claims)a schema "virtual: token" do field(:typ, :string) field(:aud, :string) field(:iss, :string) field(:sub, :string) field(:exp, :integer) field(:jwt, :string) field(:claims, :map) timestamps() end @doc """ Find one token by matching jti and aud. """ def find_by_claims(claims) do adapter().one(claims, config()) end @doc """ Create a new token based on the JWT and decoded claims. """ def create(claims, jwt) do adapter().insert(changeset(claims, jwt), config()) end @doc false def changeset(claims, jwt) do prepared_claims = claims |> Map.put("jwt", jwt) |> Map.put("claims", claims) %Token{} |> cast(prepared_claims, @allowed_fields) |> validate_required(@required_fields) end @doc """ Purge any tokens that are expired. This should be done periodically to keep your DB table clean of clutter. """ def purge_expired_tokens do timestamp = Guardian.timestamp() adapter().purge_expired_tokens(timestamp, config()) end @doc false def destroy_by_sub(sub) do adapter().delete_by_sub(sub, config()) end @doc false defp config do Application.fetch_env!(:guardian, Guardian.DB) end @doc false def destroy_token(nil, claims, jwt), do: {:ok, {claims, jwt}} def destroy_token(model, claims, jwt) do case adapter().delete(model, config()) do {:error, _} -> {:error, :could_not_revoke_token} nil -> {:error, :could_not_revoke_token} _ -> {:ok, {claims, jwt}} end end defp adapter do Keyword.get(config(), :adapter, Guardian.DB.EctoAdapter) end end