Packages

Library faciliating OpenID authentication flow throughout Phoenix application(s)

Current section

Files

Jump to
keen_auth lib storage session.ex
Raw

lib/storage/session.ex

defmodule KeenAuth.Storage.Session do
@moduledoc """
Session-based storage for KeenAuth authentication data.
This storage implementation uses Phoenix sessions (cookies) to persist
authentication state. It stores the current user and provider information.
## Cookie Size Limitation
**Important**: Cookie sessions have a 4KB size limit. OAuth tokens (especially
from providers like Azure AD/Entra) can easily exceed this limit.
By default, this storage does NOT store OAuth tokens to avoid cookie overflow.
If you need to store tokens, either:
1. **Use server-side storage** - Implement custom storage using ETS, database,
or Redis to store tokens server-side
2. **Enable token storage** - Set `store_tokens: true` in config (only if you're
sure your tokens fit within the cookie limit)
## Configuration
config :keen_auth,
storage: KeenAuth.Storage.Session,
storage_options: [
store_tokens: false # default, don't store tokens in cookie
]
## Custom Storage Example
For applications that need token storage:
defmodule MyApp.Auth.Storage do
@behaviour KeenAuth.Storage
def store(conn, provider, user, oauth_response) do
# Store tokens in database/ETS
{:ok, session} = MyApp.Sessions.create(user, oauth_response[:token])
# Only store session ID in cookie
conn = put_session(conn, :session_id, session.id)
{:ok, conn}
end
def get_access_token(conn) do
with session_id when not is_nil(session_id) <- get_session(conn, :session_id),
session <- MyApp.Sessions.get(session_id) do
session.access_token
end
end
# ... implement other callbacks
end
"""
@behaviour KeenAuth.Storage
import Plug.Conn, only: [put_session: 3, get_session: 2, delete_session: 2]
require KeenAuth.Logger, as: Log
@impl true
def store(conn, provider, mapped_user, oauth_response) do
store_tokens? = get_storage_option(conn, :store_tokens, false)
Log.debug(:storage, "Storing session", provider: provider, store_tokens: store_tokens?)
conn =
conn
|> put_provider(provider)
|> maybe_put_tokens(provider, oauth_response[:token], store_tokens?)
|> put_current_user(provider, mapped_user)
{:ok, conn}
end
defp maybe_put_tokens(conn, _provider, _tokens, false), do: conn
defp maybe_put_tokens(conn, provider, tokens, true), do: put_tokens(conn, provider, tokens)
defp get_storage_option(conn, key, default) do
config = KeenAuth.Plug.fetch_config(conn)
options = KeenAuth.Config.get(config, :storage_options, [])
Keyword.get(options, key, default)
end
@impl true
def current_user(conn) do
get_session(conn, :current_user)
end
@impl true
def authenticated?(conn) do
current_user(conn) != nil
end
@impl true
def get_access_token(conn) do
get_session(conn, :access_token)
end
@impl true
def get_id_token(conn) do
get_session(conn, :id_token)
end
@impl true
def get_refresh_token(conn) do
get_session(conn, :refresh_token)
end
@impl true
def delete(conn) do
conn
|> put_current_user()
|> put_access_token()
end
@impl true
def get_provider(conn) do
get_session(conn, :provider)
end
@impl true
def put_provider(conn, provider \\ nil)
def put_provider(conn, nil) do
delete_session(conn, :provider)
end
def put_provider(conn, provider) do
put_session(conn, :provider, provider)
end
@impl true
def put_current_user(conn, provider \\ nil, user \\ nil)
def put_current_user(conn, _provider, nil) do
delete_session(conn, :current_user)
end
def put_current_user(conn, _provider, user) do
put_session(conn, :current_user, user)
end
@impl true
def put_tokens(conn, provider, tokens) do
conn
|> put_access_token(provider, tokens["access_token"])
|> put_id_token(provider, tokens["id_token"])
|> put_refresh_token(provider, tokens["refresh_token"])
end
def put_access_token(conn, provider \\ nil, token \\ nil)
def put_access_token(conn, _provider, nil) do
conn
|> delete_session(:access_claims)
|> delete_session(:access_token)
end
def put_access_token(conn, _provider, token) do
put_session(conn, :access_token, token)
end
def put_id_token(conn, provider \\ nil, token \\ nil)
def put_id_token(conn, _provider, nil) do
delete_session(conn, :id_token)
end
def put_id_token(conn, _provider, token) do
put_session(conn, :id_token, token)
end
@spec put_refresh_token(Plug.Conn.t(), any, any) :: Plug.Conn.t()
def put_refresh_token(conn, provider \\ nil, token \\ nil)
def put_refresh_token(conn, _provider, nil) do
delete_session(conn, :refresh_token)
end
def put_refresh_token(conn, _provider, token) do
put_session(conn, :refresh_token, token)
end
end