Gateway Authentication
Every gateway request is authenticated before any tool executes. almyty enforces a default-deny policy — gateways with no auth configured reject all requests with 401.

In the UI
- Open a gateway’s detail page
- Click the Authentication tab
- Click Add Auth Method
- Select a type (API Key, Bearer Token, Basic Auth, JWT, OAuth 2.1, or None)
- Fill in the configuration and click Save
To generate API keys for the gateway, click Manage Keys after adding an API Key or Bearer Token auth method. The raw key is shown once at creation time.
Via the API
Add an auth method
curl -X POST /gateways/{id}/auth \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "api_key",
"isRequired": true,
"configuration": {
"keyHeader": "X-API-Key"
}
}'Generate an API key
curl -X POST /gateways/{id}/auth/api-keys \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Key",
"scopes": ["tools:read", "tools:execute"],
"expiresAt": "2027-01-01T00:00:00Z"
}'Response (key shown once):
{
"id": "key-uuid",
"name": "Production Key",
"key": "almyty_gw_abc123...",
"scopes": ["tools:read", "tools:execute"],
"expiresAt": "2027-01-01T00:00:00Z"
}List and revoke keys
# List keys
curl /gateways/{id}/auth/api-keys \
-H "Authorization: Bearer $TOKEN"
# Revoke a key
curl -X DELETE /gateways/{id}/auth/api-keys/{keyId} \
-H "Authorization: Bearer $TOKEN"Authentication methods
| Method | Header / Parameter | Use case |
|---|---|---|
| None | — | Public/development gateways (must be explicitly set) |
| API Key | X-API-Key header or api_key query param | Machine-to-machine |
| Bearer Token | Authorization: Bearer <token> | Programmatic access |
| Basic Auth | Authorization: Basic <base64> | Legacy integrations |
| JWT | Authorization: Bearer <jwt> | Signed, self-contained tokens |
| OAuth 2.1 | Authorization: Bearer <oauth-token> | Full authorization code flow with PKCE |
Enforcement pipeline
Every request to /mcp/*, /utcp/*, or /a2a/* passes through the same pipeline:
- Resolve the organization and gateway from the URL
- Load all active auth configs for that gateway
- If no auth configs exist, reject (401)
- Try each required auth method in order — first success wins
- If all fail, reject with the last error (401 or 403)
- If valid, execute the request
Discovery endpoints (.well-known/*, Agent Cards) are always public.
API Key and Bearer Token
Keys are stored as SHA-256 hashes. The raw key is only shown once.
# Via custom header
curl /acme/my-tools \
-H "X-API-Key: almyty_gw_abc123..."
# Via query parameter
curl "/acme/my-tools?api_key=almyty_gw_abc123..."
# Via Bearer header
curl /acme/my-tools \
-H "Authorization: Bearer almyty_gw_abc123..."Keys support optional expiry, scopes, and lastUsedAt tracking.
Basic Auth
Decodes the Authorization: Basic header, looks up the user by email, and verifies the password with bcrypt.
curl /acme/my-tools \
-H "Authorization: Basic $(echo -n 'user@example.com:password' | base64)"JWT
Verifies the JWT signature using the secret configured on the auth method (or falls back to the server’s JWT_SECRET). The payload must contain sub or userId.
curl -X POST /gateways/{id}/auth \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "jwt",
"isRequired": true,
"configuration": {
"secret": "your-jwt-signing-secret"
}
}'OAuth 2.1 (MCP OAuth)
almyty implements a full OAuth 2.1 authorization server per the MCP specification:
- Authorization Code flow with PKCE (S256 mandatory)
- Dynamic Client Registration (RFC 7591)
- Token Revocation (RFC 7009)
- Authorization Server Metadata (RFC 8414)
- Protected Resource Metadata (RFC 9728)
Discovery
curl /acme/my-tools/.well-known/oauth-authorization-server
curl /acme/my-tools/.well-known/oauth-protected-resourceClient registration
curl -X POST /acme/my-tools/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "My MCP Client",
"redirect_uris": ["http://localhost:3000/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none"
}'Authorization code flow
Step 1 — Redirect user to authorize:
GET /acme/my-tools/authorize
?response_type=code
&client_id=mcp_client_abc123...
&redirect_uri=http://localhost:3000/callback
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
&scope=tools:read tools:execute
&state=random-state-valueStep 2 — Exchange code for tokens:
curl -X POST /acme/my-tools/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code\
&code=auth_code_here\
&redirect_uri=http://localhost:3000/callback\
&client_id=mcp_client_abc123...\
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"Step 3 — Use the access token:
curl -X POST /acme/my-tools \
-H "Authorization: Bearer almyty_at_..." \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'Token lifetimes
| Token | Lifetime |
|---|---|
| Access token | 1 hour |
| Refresh token | 30 days |
| Authorization code | 10 minutes |
Refresh tokens are rotated on use. Revoking a refresh token also revokes its access tokens.
Validation rules
IP restrictions
{
"validationRules": {
"allowedIpRanges": ["10.0.0.0/8", "192.168.1.100"]
}
}Required headers
{
"validationRules": {
"requiredHeaders": ["X-Request-Id", "X-Client-Version"]
}
}Key scopes
| Scope | Description |
|---|---|
tools:read | List and view tool definitions |
tools:execute | Execute/invoke tools |
gateway:read | View gateway configuration |
Multiple auth methods
A gateway can have multiple auth methods. Each is either required or optional. Required methods are tried in order — first match wins. You can combine methods for gradual migration (e.g., add OAuth while keeping API keys active).