Custom Authentication
View Sourcebarrel_mcp provides a simplified way to integrate custom authentication systems via barrel_mcp_auth_custom. This is useful when you have an existing key management system and want to use it for MCP HTTP authentication.
Simple Interface
Instead of implementing the full barrel_mcp_auth behaviour (with init/1, authenticate/2, and challenge/2), you only need two functions:
-module(my_auth).
-export([init/1, authenticate/2]).
%% Initialize authentication state
-spec init(Opts :: map()) -> {ok, State :: term()}.
init(_Opts) ->
{ok, #{}}.
%% Authenticate a token
-spec authenticate(Token :: binary(), State :: term()) ->
{ok, AuthInfo :: map(), NewState :: term()} |
{error, Reason :: term(), NewState :: term()}.
authenticate(Token, State) ->
case my_key_store:validate(Token) of
{ok, KeyInfo} ->
AuthInfo = #{
subject => maps:get(user_id, KeyInfo),
scopes => maps:get(permissions, KeyInfo, [])
},
{ok, AuthInfo, State};
error ->
{error, invalid_token, State}
end.Usage
Configure the HTTP server to use your custom auth module:
barrel_mcp:start_http(#{
port => 9090,
auth => #{
provider => barrel_mcp_auth_custom,
provider_opts => #{
module => my_auth,
module_opts => #{} % passed to my_auth:init/1
}
}
}).Token Extraction
barrel_mcp_auth_custom automatically extracts tokens from HTTP requests. It checks (in order):
Authorization: Bearer <token>headerX-API-Key: <token>header
The extracted token is passed to your authenticate/2 function.
AuthInfo Format
Your authenticate/2 function should return a map with:
| Key | Type | Description |
|---|---|---|
subject | binary | User/client identifier |
scopes | [binary] | List of permission scopes |
Additional keys are preserved in the claims field.
Example: barrel_memory Integration
Here's how barrel_memory uses custom auth with its existing key system:
-module(barrel_memory_mcp_auth).
-export([init/1, authenticate/2]).
init(Opts) ->
{ok, Opts}.
authenticate(Token, State) ->
case barrel_memory_api_keys:validate_key(Token) of
{ok, KeyInfo} ->
AuthInfo = #{
subject => maps:get(team_id, KeyInfo, <<"unknown">>),
scopes => maps:get(permissions, KeyInfo, [])
},
{ok, AuthInfo, State};
{error, invalid_key} ->
{error, invalid_token, State}
end.Configuration in barrel_memory:
barrel_mcp:start_http(#{
port => 9091,
auth => #{
provider => barrel_mcp_auth_custom,
provider_opts => #{
module => barrel_memory_mcp_auth
}
}
}).Claude Code Configuration
Once your MCP server is running with custom auth, add it to Claude Code:
# With Bearer token
claude mcp add my-server --transport http http://localhost:9090/mcp \
--header "Authorization: Bearer your-api-key"
# Or with X-API-Key header
claude mcp add my-server --transport http http://localhost:9090/mcp \
--header "X-API-Key: your-api-key"
Error Handling
When authentication fails, barrel_mcp_auth_custom returns a 401 response with:
WWW-Authenticate: Bearer realm="mcp"Your authenticate/2 can return any error reason - it will be logged but not exposed to clients.