README.md

# Auctoritas

Session like authentication library for Elixir applications
* Documentation: [HexDocs](https://hexdocs.pm/auctoritas/api-reference.html)

# WORK IN PROGRESS
### Todo

- [ ] Session types [:sliding, :refresh_token, :static]
- [ ] Plug integration
- [x] Default data_store (Cachex; Erlang ETS)
- [ ] Redis data_store

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `auctoritas` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:auctoritas, "~> 0.2.0"}
  ]
end
```

## Basic Usage
```elixir
iex> alias Auctoritas.AuthenticationManager, as: Auth
Auctoritas.AuthenticationManager

iex> user_data = %{username: "USERNAME", password: "PASSWORD"}
%{username: "USERNAME", password: "PASSWORD"}

iex> token_data = %{user_id: 1, username: "USERNAME", email: "USERNAME@EMAIL.COM"}
%{user_id: 1, username: "USERNAME", email: "USERNAME@EMAIL.COM"}

iex> {:ok, token} = Auth.authenticate(user_data, token_data)
{:ok, "35cdc028d1623b58f616d21386d1c7982b25183776b7af69f9bb7dc0852a5095"}

iex> {:ok, data} = Auth.get_token_data(token)
{:ok,
 %Auctoritas.AuthenticationManager.DataStorage.Data{
   data: %{email: "USERNAME@EMAIL.COM", user_id: 1, username: "USERNAME"},
   metadata: %{
     expires_in: 86385250,
     inserted_at: 1547158890,
     updated_at: 1547158890
   }
 }}
 
 iex> {:ok, data} = Auth.deauthenticate(token)
 {:ok, true}
```

## Configuration
```elixir
config :auctoritas, :config,
    name: "auctoritas_default", # Custom name if you need multiple auctoritas authentication managers
    data_storage: Auctoritas.AuthenticationManager.DataStorage, # Custom data_storage implementation (default is Cachex)
    token_manager: Auctoritas.AuthenticationManager.DefaultTokenManager, # Custom token_manager implementation
    expiration: 86400 # Token expiration timer in second

```

## Spawning Auctoritas authentication managers
```elixir
iex> alias Auctoritas.AuthenticationManager, as: Auth
Auctoritas.AuthenticationManager

iex> alias Auctoritas.Config
Auctoritas.Config

iex> config = Config.new(name: "custom_name", token_manager: CustomTokenManager, expiration: 120)
%Auctoritas.Config{
  data_storage: Auctoritas.AuthenticationManager.DataStorage,
  expiration: 120,
  name: "custom_name",
  token_manager: CustomTokenManager
}

iex> alias Auctoritas.AuthenticationSupervisor
Auctoritas.AuthenticationSupervisor

iex> AuthenticationSupervisor.start_link(config)
{:ok, #PID<0.278.0>}

iex> {:ok, token} = Auth.authenticate("custom_name", %{username: "username"}, %{})
{:ok, "3acbc9f1362ba9fb09fc3db6e4e1f6cfa5fcd2738156d11461cab3bd0ed92940"}
```

## Implementing token_manager
For custom token_manager you need to implement `Auctoritas.TokenManager` behaviour
```elixir
defmodule Auctoritas.TokenManager do
  @type token() :: String.t()
  @type name() :: String.t()

  @callback generate_token(name(), any()) :: {atom(), token()}
  @callback authentification_data_check(name(), any()) :: {atom(), any()}
  @callback data_check(name(), any()) :: {atom(), any()}
end
```
Simplest way to implement `Auctoritas.TokenManager` behaviour is to inject default TokenManager into your own module with `__using__` macro
```elixir
defmodule CustomTokenManager do
  use Auctoritas.AuthenticationManager.TokenManager
end
```
Now you can override default functions to suit your own needs
```elixir
defmodule CustomTokenManager do
  use Auctoritas.AuthenticationManager.TokenManager
  
    @spec authentification_data_check(name(), map()) :: {atom(), any()}
    def authentification_data_check(name, data) when is_bitstring(name) and is_map(data) do
        case data do
          %{password: "secret_password"} -> {:ok, data}
          _ -> {:error, "Invalid user credentials"}
        end
    end
end
```