Packages

Client SDK for ClerkJS https://clerk.com/docs/reference/backend-api

Current section

Files

Jump to
clerk lib authentication_plug.ex
Raw

lib/authentication_plug.ex

defmodule Clerk.AuthenticationPlug do
@moduledoc """
Plug for authenticating requests.
## Options
* `:session_key` - the cookie name to read the session token from.
Defaults to `"__session"`.
* `:fetch_user` - when `true`, fetches the full user object from the
Clerk Backend API after token verification and assigns it as
`:current_user`. When `false`, builds `:current_user` from the JWT
claims alone (no network request). Defaults to `true`.
* `:config` - a `%Clerk.Config{}` for verification and API calls.
Defaults to `Clerk.config/0`. Required when running multiple Clerk
tenants in an umbrella app.
## Examples
# Fetches user from Clerk API on every request (default)
plug Clerk.AuthenticationPlug
# Skip the API call — use JWT claims only
plug Clerk.AuthenticationPlug, fetch_user: false
# Use an explicit Clerk config (umbrella apps)
plug Clerk.AuthenticationPlug, config: config
"""
@behaviour Plug
@impl true
def init(opts), do: opts
@impl true
def call(conn, opts) do
session_key = Keyword.get(opts, :session_key, "__session")
fetch_user? = Keyword.get(opts, :fetch_user, true)
config_opts = Keyword.take(opts, [:config])
with {:ok, token} <- get_auth_token(conn, session_key),
{:ok, %{"sub" => user_id} = claims} <-
Clerk.Session.verify_and_validate(token, config_opts),
{:ok, user} <- maybe_fetch_user(user_id, claims, fetch_user?, config_opts) do
conn
|> Plug.Conn.assign(:clerk_session, claims)
|> Plug.Conn.assign(:current_user, user)
else
_ ->
conn
|> Plug.Conn.send_resp(401, "Unauthorized")
|> Plug.Conn.halt()
end
end
defp maybe_fetch_user(user_id, _claims, true, config_opts),
do: Clerk.User.get(user_id, config_opts)
defp maybe_fetch_user(_user_id, claims, false, _config_opts) do
{:ok,
%{
"id" => claims["sub"],
"email" => claims["email"],
"first_name" => claims["first_name"],
"last_name" => claims["last_name"]
}}
end
defp get_auth_token(conn, session_key) do
case get_token_from_header(conn) do
token when is_binary(token) ->
{:ok, token}
nil ->
case Map.fetch(conn.req_cookies, session_key) do
{:ok, session} -> {:ok, session}
_ -> {:error, :unauthorized}
end
end
end
defp get_token_from_header(conn) do
case Plug.Conn.get_req_header(conn, "authorization") do
["Bearer " <> token] -> token
_ -> nil
end
end
end