defmodule Rivet.Auth.Token.Validation do
alias Rivet.Auth
alias Rivet.Ident
require Logger
##############################################################################
@spec jwt(
target :: Ident.User.t() | Ident.Factor.t(),
hostname :: String.t(),
scope :: map(),
# note: offset is used for tests only
testing_only_expiration_offset :: nil | integer()
) ::
{:ok, token :: String.t(), claims :: map(), Ident.Factor.t()}
| {:error, String.t()}
def jwt(target, hostname, scope \\ %{}, offset \\ 0)
# # # # # # # # # #
def jwt(%Ident.Factor{details: %{type: type}} = factor, hostname, scope, offset)
when is_binary(hostname) do
val_age = Auth.Settings.expire_limit(:val, type) + offset
scope = %{type: type} |> Map.merge(scope)
with {:ok, tok, claims} <-
Auth.Token.Create.jwt(:val, "cas1:#{factor.id}", hostname, val_age, nil, scope) do
{:ok, tok, claims, factor}
end
end
# # # # # # # # # #
def jwt(%Ident.User{} = user, hostname, scope, offset) when is_binary(hostname) do
val_age = Auth.Settings.expire_limit(:val, :acc) + offset
secret = Ident.Factor.Password.generate()
# create a validation JWT
case Ident.Factor.create(%{
name: "valtok",
user_id: user.id,
type: :valtok,
value: secret,
details: %{type: "acc"},
expires_at: System.os_time(:second) + val_age
}) do
{:ok, %Ident.Factor{} = factor} ->
with {:ok, tok, claims, _factor} <- jwt(factor, hostname, scope, offset) do
{:ok, tok, claims, factor}
end
{:error, %{errors: [expires_at: {"is invalid", _}]}} ->
Logger.error("Unable to create Auth Auth.Token record in DB! Invalid Expiration.")
{:error, "Invalid Expiration"}
error ->
Logger.error("Unable to create Auth Auth.Token record in DB! #{inspect(error)}")
error
end
end
##############################################################################
@spec key(hostname :: String.t(), Ident.User.t()) :: {:ok, map()} | {:error, String.t(), any()}
def key(hostname, %Ident.User{} = user) do
with {:ok, token, _, %Ident.Factor{value: secret}} <- jwt(user, hostname) do
{:ok,
%{
sub: "cas2:#{token}",
aud: "caa1:ref:#{hostname}",
sec: secret,
next: "/auth/v1/api/refresh"
}}
else
err ->
{:error, "Unable to create validaton token", err}
end
end
end