# Auth
Auth is application-owned. FastestMCP keeps a small runtime contract that turns
credentials or framework state into normalized request context:
- `ctx.principal`
- `ctx.auth`
- `ctx.capabilities`
- `Context.client_id/1`
Your application verifies sessions, tokens, cookies, or upstream identity using
its normal stack. FastestMCP only needs the normalized result.
## Function Auth
Pass a function directly when auth is specific to the host application:
```elixir
FastestMCP.server("app")
|> FastestMCP.add_auth(fn input, _ctx ->
case MyApp.Auth.verify_mcp_request(input) do
{:ok, user} ->
{:ok,
%{
principal: %{"sub" => to_string(user.id)},
auth: %{source: :app, user_id: user.id},
capabilities: MyApp.MCPScopes.for_user(user)
}}
:error ->
{:error, :unauthorized}
end
end)
```
The function may have arity 2 or 3. Arity 3 receives the configured auth
options as the third argument.
## Module Auth
Use the behaviour when you want a reusable authenticator module:
```elixir
defmodule MyApp.MCPAuth do
@behaviour FastestMCP.Auth
@impl true
def authenticate(input, _ctx, opts) do
with {:ok, user} <- MyApp.Auth.verify(input, opts) do
{:ok,
%FastestMCP.Auth.Result{
principal: %{"sub" => to_string(user.id)},
auth: %{source: :app, user_id: user.id},
capabilities: MyApp.MCPScopes.for_user(user)
}}
end
end
end
FastestMCP.server("app")
|> FastestMCP.add_auth(MyApp.MCPAuth, audience: "mcp")
```
Auth errors should return `{:error, :unauthorized}`,
`{:error, :forbidden}`, `{:error, {code, message}}`, or
`{:error, %FastestMCP.Error{}}`.
## Phoenix Assigns
When the HTTP transport runs behind Plug or Phoenix authentication, copy selected
`conn.assigns` into auth input with `auth_assigns:`. Assigns are available only
to the auth function or module under `"assigns"`; they are not added to normal
handler request metadata.
```elixir
pipeline :mcp do
plug :fetch_session
plug MyAppWeb.UserAuth, :fetch_current_user
end
scope "/" do
pipe_through :mcp
forward "/mcp", FastestMCP.Transport.HTTPApp,
server_name: MyApp.MCPServer,
path: "/mcp",
auth_assigns: [:current_user]
end
```
`FastestMCP.Auth.from_assign/2` turns one assign into a normalized auth result:
```elixir
FastestMCP.server(MyApp.MCPServer)
|> FastestMCP.add_auth(
FastestMCP.Auth.from_assign(:current_user,
principal: fn user -> %{"sub" => to_string(user.id)} end,
capabilities: fn user -> MyApp.MCPScopes.for_user(user) end,
auth: fn user -> %{source: :phoenix, user_id: user.id} end
)
)
```
`auth_assigns:` accepts:
- `false` or `nil` to copy no assigns
- `[:current_user, :account]` to copy specific assigns
- `:all` to copy every assign
The default is `false`.
## Static Token
`FastestMCP.Auth.StaticToken` is kept for local development, integration tests,
and hermetic tooling:
```elixir
FastestMCP.server("dev")
|> FastestMCP.add_auth(FastestMCP.Auth.StaticToken,
tokens: %{
"dev-token" => %{
client_id: "local-client",
scopes: ["tools:call"],
principal: %{"sub" => "local-client"}
}
},
required_scopes: ["tools:call"]
)
|> FastestMCP.add_tool("whoami", fn _arguments, ctx ->
%{principal: ctx.principal, auth: ctx.auth}
end)
```
Static tokens can be supplied as an HTTP bearer token, as `"authorization"` in
direct `auth_input`, or as `"token"` in direct `auth_input`.
## Component Authorization
Authentication identifies the caller. Component authorization decides which
tools, resources, prompts, and templates the caller may see or call.
```elixir
FastestMCP.server("app")
|> FastestMCP.add_tool("admin_report", &MyApp.Report.run/2,
auth: FastestMCP.Authorization.require_scopes(["admin:reports"])
)
```
Authorization rules can also filter list results with tags:
```elixir
FastestMCP.Authorization.restrict_tag("internal")
```
## HTTP Behavior
HTTP auth failures use plain bearer challenges:
```text
WWW-Authenticate: Bearer error="invalid_token", error_description="missing credentials"
```
FastestMCP does not serve OAuth discovery, authorization, token, callback, or
protected-resource metadata routes. Applications that need those endpoints
should expose them from their Plug or Phoenix application and pass normalized
auth results into FastestMCP.
## Why This Shape
Phoenix applications usually already own authentication, sessions, user loading,
authorization policy, and audit metadata. Keeping FastestMCP auth as a small
contract avoids a second identity stack while preserving consistent context for
handlers, middleware, tasks, transports, and component visibility.