Every API starts with trust.
And trust is earned at the boundary.
You can build fast endpoints. Return beautiful JSON. Document your data contracts.
But if anyone can call it without proving who they are?
You don’t have a platform. You have an open invitation to abuse, leaks, and chaos.
Authentication isn’t a bolt-on. It’s a first principle.
And in Phoenix, you have the tools to get it right — if you start with clarity.
Phoenix Doesn’t Prescribe — It Empowers
Phoenix doesn’t force cookies, JWTs, sessions, or OAuth.
Instead, it gives you full control over the request lifecycle.
That flexibility is power — and responsibility.
For APIs, Sessions Don’t Belong
You’re not rendering views. You’re serving:
- Mobile apps
- Frontend SPAs
- Embedded clients
- Third-party tools
These speak one language:
HTTP + Bearer token in the Authorization
header
Step 1: Plug Authentication at the Router
Start in your router. Define an authenticated pipeline:
pipeline :api_auth do
plug :accepts, ["json"]
plug MyAppWeb.Plugs.Authenticate
end
scope "/api/v1", MyAppWeb do
pipe_through :api_auth
get "/me", UserController, :show
end
Step 2: Implement the Authenticate
Plug
This plug extracts and validates the token:
defmodule MyAppWeb.Plugs.Authenticate do
import Plug.Conn
def init(opts), do: opts
def call(conn, _opts) do
with ["Bearer " <> token] <- get_req_header(conn, "authorization"),
{:ok, user} <- MyApp.Auth.verify_token(token) do
assign(conn, :current_user, user)
else
_ -> conn |> send_resp(401, "Unauthorized") |> halt()
end
end
end
- JWT? Decode and verify claims.
- Opaque token? Look it up hashed in the DB.
Once verified, assign to conn.assigns.current_user
— and you're done.
Step 3: Keep Controllers Clean
Because the plug handles auth, your controllers can stay focused:
def show(conn, _params) do
user = conn.assigns.current_user
render(conn, "user.json", user: user)
end
No token logic here. Just business logic.
JWT vs. Database Tokens
JWTs
✅ Stateless
✅ Fast to verify
⚠️ Can’t revoke easily
⚠️ Can’t track usage
DB Tokens
✅ Revocable
✅ Traceable
✅ Rotatable
⚠️ Requires storage and lookup
Pick what fits. Control vs. convenience.
Scope & Role-Based Access
Token validity is just the start.
Ask: What does this token authorize?
- Admins ≠ Regular users
- 3rd-party clients ≠ Internal services
- Mobile apps ≠ Browsers
Centralize access logic:
- Define roles and scopes
- Create helpers:
def require_admin(conn, _opts) do
if conn.assigns.current_user.role != "admin" do
conn |> send_resp(403, "Forbidden") |> halt()
else
conn
end
end
- Use macros or plugs:
plug :require_admin when action in [:delete, :update]
Observability: Audit Everything
If you authenticate requests, log them.
Logger.metadata(user_id: user.id, scope: "read:reports")
Logger.info("API request to /api/v1/reports")
Log:
user_id
request path
origin IP
scopes used
🔍 It’s how you trace abuse, debug performance issues, and enable audits.
Rate Limiting: Identity-Aware Throttling
Once you know who’s calling — throttle them.
- Use naive in-memory limiters
- Or plug in Redis buckets
plug MyAppWeb.Plugs.RateLimiter, scope: :user
Different tokens, different limits:
- 3rd-party apps? Tight leash
- Internal clients? Looser limits
- Admin tokens? Unlimited
Give Clear Errors
Bad tokens happen. Expired, revoked, malformed.
Don’t just return 401 Unauthorized
.
Return structured errors:
{
"error": "token_expired",
"message": "Your token has expired. Please log in again."
}
Your clients deserve clarity — especially if they’re not under your control.
OAuth? You Can Build It
Phoenix doesn’t ship OAuth — but Ueberauth does.
You can:
- Issue access/refresh tokens
- Validate client credentials
- Manage scopes and grant types
And plug it all right into your Phoenix pipelines.
Your API becomes an auth provider — not just a consumer.
Authentication Isn’t Just About Access. It’s About Confidence.
When you deploy to production, you want to know:
✅ Every request is authenticated
✅ Every token is scoped
✅ Every action is authorized
✅ Every event is logged
✅ Every risk is throttled
✅ Every error is clear
That’s not just security — that’s professionalism.
Build APIs Like a Pro
Your API is the foundation.
Frontends change. Devices evolve. But APIs endure.
It’s not just about fast endpoints.
It’s about building trust — with users, partners, and your future team.
Want the Full Picture?
If you're serious about building production-grade apps with Phoenix LiveView, grab the guide:
Phoenix LiveView: The Pro's Guide to Scalable Interfaces and UI Patterns
- 20 pages of expert insights
- Real-world patterns
- Advanced LiveView techniques
Whether you're designing from scratch or scaling what you’ve built, this guide will make you faster, smarter, and more confident with Phoenix.
Top comments (0)