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