Pike
A lightweight Elixir library for API key authentication and fine-grained authorization.
Key Features
- API key management
- Policy-based authorization for granular control.
- Pluggable architecture for easy integration.
- Minimal dependencies and high performance.
README
Pike
Pike enables API key enforcement with zero external dependencies, pluggable storage backends, resource-aware permissions, and a flexible DSL for defining authorization at the controller and action level.
Chapters
Usage
Installation
Add Pike to your dependencies:
def deps do
[
{:pike, "~> 0.1.0"}
]
end
Configuration
Global application-wide config (only needed if overriding defaults):
config :pike,
store: YourApp.APIStore,
on_auth_failure: {Pike.Responder.Default, :auth_failed}
Create your ETS Table:
defmodule YourApp.APIStore do
use Pike.Store.ETS, table_name: :default_api_keys
end
Using Plug
At its simplest:
plug Pike.AuthorizationPlug
๐ Multiple Pipelines
You can defineindependent pipelinesfor different API key types:
pipeline :public_api do
plug Pike.AuthorizationPlug,
store: YourApp.APIStore,
assign_to: :public_api_key
end
pipeline :partner_api do
plug Pike.AuthorizationPlug,
store: YourApp.AlternativeAPIStore,
on_auth_failure: {MyApp.Responder, :auth_failed},
assign_to: :partner_key
end
Then route accordingly:
scope "/v1/public", MyAppWeb do
pipe_through [:api, :public_api]
end
scope "/v1/partner", MyAppWeb do
pipe_through [:api, :partner_api]
end
Controller Integration
Declare expected permissions using a DSL:
defmodule MyAppWeb.ProductController do
use MyAppWeb, :controller
use Pike.Authorization, resource: "Products"
# Uses controller-level resource ("Products")
@require_permission action: :read
def index(conn, _params), do: # ...
# Resource becomes "ProductsMeta"
@require_permission action: :read, append: "Meta"
def meta(conn, _params), do: # ...
# Completely overrides: resource = "VariableProducts"
@require_permission action: :read, override: "VariableProducts"
def variations(conn, _params), do: # ...
end
Permission Model
Each API key must define a list of permissions:
%{
key: "abc123",
permissions: [
%{resource: "Products", scopes: [:read, :write]},
%{resource: "ProductsMeta", scopes: [:read]},
%{resource: "VariableProducts", scopes: [:read]}
]
}
Key Assignment
After successful authentication, the API key is available via:
conn.assigns[:pike_api_key] # or :partner_api_key if overridden
This lets you:
- Inspect the key
- Track usage
- Enforce tenant or user-level scoping
Key Management
Pike provides functions for managing API keys:
# Create a new key
Pike.insert(%{
key: "abc123",
enabled: true, # Optional, defaults to true
permissions: [
%{resource: "Products", scopes: [:read, :write]}
]
})
# Enable/disable a key
Pike.disable_key("abc123")
Pike.enable_key("abc123")
# Check if a key is enabled
Pike.key_enabled?("abc123")
# Delete a key
Pike.delete_key("abc123")
# Update a key
Pike.update_key("abc123", %{
permissions: [
%{resource: "Products", scopes: [:read]}
]
})
Disabled keys will return a:disabled
error reason, which is handled by the responder.
Store Backend
Pike uses a pluggable store interface:
@callback get_key(String.t()) :: {:ok, map()} | :error | {:error, :disabled}
@callback action?(map(), resource :: String.t(), action :: atom()) :: boolean()
@callback insert(map()) :: :ok | {:error, term()} # optional
@callback delete_key(String.t()) :: :ok | {:error, term()} # optional
@callback update_key(String.t(), map()) :: :ok | {:error, term()} # optional
You can provide your own module and configure it per plug or globally.
๐ License
MIT
License
Pike is released under theMIT License.