Current section
Files
Jump to
Current section
Files
lib/storage.ex
defmodule KeenAuth.Storage do
@moduledoc """
Defines the storage behavior for persisting authentication data.
Storage is the final stage in KeenAuth's pipeline architecture. It handles
persisting user data, tokens, and session information. Storage implementations
can be as simple as session-based or as sophisticated as multi-layer persistence.
## Pipeline Stage
The storage is the final stage in the authentication flow:
```
Strategy → Mapper → Processor → **Storage**
```
## Flexibility
Storage implementations can vary based on your needs:
- **Session Storage** (default): Simple session-based storage
- **Database Storage**: Persistent user sessions in database
- **JWT Storage**: Stateless authentication with JWT tokens
- **Multi-layer**: Combine database + session + JWT for different purposes
## Example Implementation
defmodule MyApp.Auth.DatabaseStorage do
@behaviour KeenAuth.Storage
def store(conn, provider, user, oauth_response) do
{:ok, session} = create_user_session(user, provider)
conn = put_session(conn, :session_id, session.id)
{:ok, conn}
end
def current_user(conn) do
with session_id when not is_nil(session_id) <- get_session(conn, :session_id),
session when not is_nil(session) <- get_session_from_db(session_id) do
session.user
else
_ -> nil
end
end
# ... implement other callbacks
end
## Configuration
Configure a custom storage implementation:
config :keen_auth,
storage: MyApp.Auth.CustomStorage
"""
alias KeenAuth.AuthenticationController
alias KeenAuth.Config
@default_storage KeenAuth.Storage.Session
@callback store(
conn :: Plug.Conn.t(),
provider :: atom(),
mapped_user :: KeenAuth.User.t() | map(),
oauth_response :: AuthenticationController.oauth_callback_response() | nil
) :: {:ok, Plug.Conn.t()}
@callback current_user(conn :: Plug.Conn.t()) :: any() | nil
@callback authenticated?(conn :: Plug.Conn.t()) :: boolean()
@callback get_access_token(conn :: Plug.Conn.t()) :: binary() | nil
@callback get_id_token(conn :: Plug.Conn.t()) :: binary() | nil
@callback get_refresh_token(conn :: Plug.Conn.t()) :: binary() | nil
@callback get_provider(conn :: Plug.Conn.t()) :: binary() | nil
@callback delete(conn :: Plug.Conn.t()) :: Plug.Conn.t()
@callback put_provider(conn :: Plug.Conn.t(), provider :: atom()) :: Plug.Conn.t()
@callback put_tokens(conn :: Plug.Conn.t(), provider :: atom(), AuthenticationController.tokens_map()) :: Plug.Conn.t()
@callback put_current_user(conn :: Plug.Conn.t(), provider :: atom(), KeenAuth.User.t() | map()) :: Plug.Conn.t()
defmacro __using__(_params \\ nil) do
quote do
@behaviour unquote(__MODULE__)
def process(conn, provider, mapped_user, oauth_response), do: unquote(__MODULE__).process(conn, provider, mapped_user, oauth_response)
def store(conn, provider, mapped_user, oauth_response), do: unquote(__MODULE__).store(conn, provider, mapped_user, oauth_response)
def current_user(conn), do: unquote(__MODULE__).current_user(conn)
def authenticated?(conn), do: unquote(__MODULE__).authenticated?(conn)
def authenticated?(conn), do: unquote(__MODULE__).authenticated?(conn)
def get_access_token(conn), do: unquote(__MODULE__).get_access_token(conn)
def get_id_token(conn), do: unquote(__MODULE__).get_id_token(conn)
def get_refresh_token(conn), do: unquote(__MODULE__).get_refresh_token(conn)
def get_provider(conn), do: unquote(__MODULE__).get_provider(conn)
def delete(conn), do: unquote(__MODULE__).delete(conn)
def put_provider(conn, provider), do: unquote(__MODULE__).put_provider(conn, provider)
def put_tokens(conn, provider, tokens), do: unquote(__MODULE__).put_tokens(conn, provider, tokens)
def put_current_user(conn, provider, user), do: unquote(__MODULE__).put_current_user(conn, provider, user)
defoverridable unquote(__MODULE__)
end
end
def store(conn, provider, mapped_user, oauth_response) do
current_storage(conn).store(conn, provider, mapped_user, oauth_response)
end
def current_user(conn) do
current_storage(conn).current_user(conn)
end
def authenticated?(conn) do
current_storage(conn).authenticated?(conn)
end
def get_access_token(conn) do
current_storage(conn).get_access_token(conn)
end
def get_id_token(conn) do
current_storage(conn).get_id_token(conn)
end
def get_refresh_token(conn) do
current_storage(conn).get_refresh_token(conn)
end
def get_provider(conn) do
current_storage(conn).get_provider(conn)
end
def delete(conn) do
current_storage(conn).delete(conn)
end
def put_provider(conn, provider) do
current_storage(conn).put_provider(conn, provider)
end
def put_tokens(conn, provider, tokens) do
current_storage(conn).put_tokens(conn, provider, tokens)
end
def put_current_user(conn, provider, user) do
current_storage(conn).put_current_user(conn, provider, user)
end
def current_storage(conn) do
KeenAuth.Plug.fetch_config(conn)
|> get_storage()
end
def get_storage(config) do
Config.get(config, :storage, @default_storage)
end
end