defmodule AshAuthentication.TokenResource.GetTokenPreparation do @moduledoc """ Constrains a query to only records which match the `jti` or `token` argument and optionally by the `purpose` argument. """ use Ash.Resource.Preparation alias Ash.{Error.Query.InvalidArgument, Query, Resource.Preparation} alias AshAuthentication.Jwt require Ash.Query @doc false @impl true @spec prepare(Query.t(), keyword, Preparation.context()) :: Query.t() def prepare(query, _, _) do jti = get_jti(query) purpose = Query.get_argument(query, :purpose) query |> Query.filter(jti: jti) |> then(fn query -> if purpose, do: Query.filter(query, purpose: purpose), else: query end) |> Query.filter(expires_at > now()) end defp get_jti(query), do: get_jti(Query.get_argument(query, :jti), Query.get_argument(query, :token)) defp get_jti(jti, _token) when byte_size(jti) > 0, do: jti defp get_jti(_jti, token) when byte_size(token) > 0 do token |> Jwt.peek() |> case do {:ok, %{"jti" => jti}} -> jti _ -> get_jti(nil, nil) end end defp get_jti(_jti, _token), do: raise( InvalidArgument.exception( field: :jti, message: "At least one of `jti` or `token` arguments must be present" ) ) end