defmodule Curator.SessionKeeper do @moduledoc """ A module that provides claims based authentication for Elixir applications. Curator.SessionKeeper provides the framework for using claims in any Elixir application, web based or otherwise, where authentication is required. ## Configuration config :curator_session_keeper, Curator.SessionKeeper, serializer: MyApp.Curator.SessionKeeperSerializer, """ import Curator.SessionKeeper.Utils unless Application.get_env(:curator_session_keeper, Curator.SessionKeeper) do raise "Curator.SessionKeeper is not configured" end unless Keyword.get(Application.get_env(:curator_session_keeper, Curator.SessionKeeper), :serializer) do raise "Curator.SessionKeeper requires a serializer" end @doc false def hooks_module, do: config(:hooks, Curator.SessionKeeper.Hooks.Default) @doc """ Fetch the configured serializer module """ @spec serializer() :: atom def serializer, do: config(:serializer) @doc """ Verify the given claims. """ @spec verify_claims(map) :: {:ok, map} | {:error, any} def verify_claims(claims) do Curator.SessionKeeper.hooks_module.verify_claims(claims) end @doc false def config, do: Application.get_env(:curator_session_keeper, Curator.SessionKeeper) @doc false def config(key, default \\ nil), do: config() |> Keyword.get(key, default) |> resolve_config(default) defp resolve_config({:system, var_name}, default), do: System.get_env(var_name) || default defp resolve_config(value, _default), do: value @doc """ build claims from a resource. The resource will be run through the configured serializer to obtain a value suitable for storage inside the claims. """ @spec build_claims(any) :: {:ok, map} | {:error, any} def build_claims(resource), do: build_claims(resource, %{}) @doc false def build_claims(resource, claims) when is_list(claims) do build_claims(resource, Enum.into(claims, %{})) end @doc """ Like build_claims/1 but also add anything found inside the claims map into the built claims. ### Example Curator.SessionKeeper.build_claims( user, %{} ) """ @spec build_claims(any, map) :: {:ok, map} | {:error, any} def build_claims(resource, claims) do case Curator.SessionKeeper.serializer.for_token(resource) do {:ok, sub} -> full_claims = claims |> stringify_keys |> Curator.SessionKeeper.Claims.app_claims |> Curator.SessionKeeper.Claims.sub(sub) Curator.SessionKeeper.hooks_module.build_claims(resource, full_claims) {:error, reason} -> {:error, reason} end end end