Skip to Content
almyty docs — v1
GatewaysGateway Authentication

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.

Gateways page — empty state

In the UI

  1. Open a gateway’s detail page
  2. Click the Authentication tab
  3. Click Add Auth Method
  4. Select a type (API Key, Bearer Token, Basic Auth, JWT, OAuth 2.1, or None)
  5. 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

MethodHeader / ParameterUse case
NonePublic/development gateways (must be explicitly set)
API KeyX-API-Key header or api_key query paramMachine-to-machine
Bearer TokenAuthorization: Bearer <token>Programmatic access
Basic AuthAuthorization: Basic <base64>Legacy integrations
JWTAuthorization: Bearer <jwt>Signed, self-contained tokens
OAuth 2.1Authorization: Bearer <oauth-token>Full authorization code flow with PKCE

Enforcement pipeline

Every request to /mcp/*, /utcp/*, or /a2a/* passes through the same pipeline:

  1. Resolve the organization and gateway from the URL
  2. Load all active auth configs for that gateway
  3. If no auth configs exist, reject (401)
  4. Try each required auth method in order — first success wins
  5. If all fail, reject with the last error (401 or 403)
  6. 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-resource

Client 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-value

Step 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

TokenLifetime
Access token1 hour
Refresh token30 days
Authorization code10 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

ScopeDescription
tools:readList and view tool definitions
tools:executeExecute/invoke tools
gateway:readView 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).