Gateway Admin Guide
Deploy, configure, and manage a Simplaix Gateway instance.
This guide is for platform administrators who deploy and operate a Simplaix Gateway instance. You'll learn how to configure authentication, manage users and agents, define access policies, set up credential providers, and monitor the system.
Overview
As a Gateway Admin you are responsible for:
- Deploying the Gateway and configuring environment variables
- Managing users and assigning roles
- Registering agents and issuing runtime tokens
- Configuring tool providers (MCP servers) and access policies
- Setting up credential providers for the credential vault
- Monitoring via audit logs
Quick Start
Install the Gateway CLI globally and scaffold a config:
npm install -g @simplaix/simplaix-gateway
gateway init
gateway start
gateway admin create --email admin@example.com --password changemeThe Gateway starts on port 7521 by default. See Deployment for production deployment options.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
JWT_SECRET | Yes | — | Secret for signing/verifying JWTs (min 32 chars) |
JWT_PUBLIC_KEY | No | — | PEM public key for asymmetric JWT (RSA/EC) |
JWT_ISSUER | No | simplaix-gateway | JWT iss claim |
JWT_AUDIENCE | No | — | JWT aud claim |
JWT_EXPIRES_IN | No | 24h | Token expiration |
JWT_EXTERNAL_ISSUERS | No | — | JSON array of external IdP configs |
ADMIN_EMAIL | No | — | Auto-created admin on first boot |
ADMIN_PASSWORD | No | — | Password for auto-created admin |
DATABASE_URL | No | SQLite ~/.simplaix-gateway/data/gateway.db | SQLite file: path or postgres:// URL |
CREDENTIAL_ENCRYPTION_KEY | Yes | — | 64-char hex key for AES-256-GCM |
PORT | No | 7521 | HTTP port |
GATEWAY_PUBLIC_URL | No | — | Public base URL for OAuth callbacks and pairing links |
OAUTH_CALLBACK_BASE_URL | No | — | Override OAuth callback base separately |
MCP_SERVER_URL | No | http://localhost:8080 | Default MCP server URL |
External identity providers
To accept JWTs from Auth0, Azure AD, Okta, etc.:
# OIDC / JWKS
JWT_EXTERNAL_ISSUERS='[{
"issuer": "https://your-tenant.auth0.com/",
"jwksUri": "https://your-tenant.auth0.com/.well-known/jwks.json",
"audience": "simplaix-gateway"
}]'
# Shared secret (HS256)
JWT_EXTERNAL_ISSUERS='[{
"issuer": "https://auth.example.com",
"secret": "shared-secret",
"audience": "simplaix-gateway"
}]'User Management
Roles
| Role | Permissions |
|---|---|
admin | Full access — manage all users, agents, providers, audit logs across all tenants |
tenant_admin | Admin within own tenant — manage agents, providers, policies, view tenant audit logs |
agent_creator | Create and manage own agents, view own audit logs |
Create a user
curl -X POST https://<your-gateway-url>/api/v1/admin/users \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"email": "dev@example.com",
"password": "securepass123",
"name": "Alice",
"tenantId": "tenant-acme",
"roles": ["agent_creator"]
}'roles defaults to ["agent_creator"] if omitted.
Manage roles
# Assign a role
curl -X POST https://<your-gateway-url>/api/v1/admin/users/<user-id>/roles \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{"role": "tenant_admin"}'
# Remove a role
curl -X DELETE https://<your-gateway-url>/api/v1/admin/users/<user-id>/roles/tenant_admin \
-H "Authorization: Bearer <admin-jwt>"List and delete users
# List all users
curl https://<your-gateway-url>/api/v1/admin/users \
-H "Authorization: Bearer <admin-jwt>"
# Delete a user
curl -X DELETE https://<your-gateway-url>/api/v1/admin/users/<user-id> \
-H "Authorization: Bearer <admin-jwt>"Agent Management
Register an agent
curl -X POST https://<your-gateway-url>/api/v1/admin/agents \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Support Agent",
"upstreamUrl": "http://support-agent:8000",
"description": "Handles customer inquiries",
"tenantId": "tenant-acme"
}'Request fields:
| Field | Required | Description |
|---|---|---|
name | Yes | Display name |
upstreamUrl | Yes | URL of the agent runtime |
upstreamSecret | No | Bearer token sent to the upstream runtime |
description | No | Human-readable description |
requireConfirmation | No | Require confirmation for all tool calls (default: false) |
requiredCredentials | No | Credential requirements for the agent |
tenantId | No | Tenant scope |
The response includes a runtime_token (art_...) — store it immediately, it is shown only once.
{
"success": true,
"agent": {
"id": "abc123",
"name": "Support Agent",
"upstreamUrl": "http://support-agent:8000",
"isActive": true,
"requireConfirmation": false,
"runtimeTokenPrefix": "art_xxxx",
"createdAt": "2025-01-15T10:00:00Z"
},
"runtime_token": "art_xxxxxxxxxxxxxxxx..."
}Kill switch
# Disable — all invocations immediately return 403
curl -X POST https://<your-gateway-url>/api/v1/admin/agents/<id>/disable \
-H "Authorization: Bearer <admin-jwt>"
# Re-enable
curl -X POST https://<your-gateway-url>/api/v1/admin/agents/<id>/enable \
-H "Authorization: Bearer <admin-jwt>"Regenerate runtime token
curl -X POST https://<your-gateway-url>/api/v1/admin/agents/<id>/regenerate-token \
-H "Authorization: Bearer <admin-jwt>"
# Returns a new runtime_token — the old one is immediately invalidatedAPI Key Management
API keys (gk_ prefix) provide server-to-server authentication for agent runtimes or external services calling the Gateway.
Create an API key
curl -X POST https://<your-gateway-url>/api/v1/admin/api-keys \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Agent Server",
"scopes": ["credentials:resolve"]
}'The full key is returned once in the response — store it securely.
Scopes
| Scope | Description |
|---|---|
credentials:resolve | Resolve user credentials for injection (default) |
credentials:read | Read credential metadata |
credentials:write | Store/update credentials on behalf of users |
List and revoke
# List (shows keyPrefix, not the full key)
curl https://<your-gateway-url>/api/v1/admin/api-keys \
-H "Authorization: Bearer <admin-jwt>"
# Revoke
curl -X DELETE https://<your-gateway-url>/api/v1/admin/api-keys/<key-id> \
-H "Authorization: Bearer <admin-jwt>"Tool Provider Management
Tool Providers map glob patterns to upstream MCP server endpoints — they define where tool calls are routed.
Create a tool provider
curl -X POST https://<your-gateway-url>/api/v1/admin/tool-providers \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Slack MCP",
"pattern": "slack_*",
"endpoint": "http://slack-mcp:3000",
"authType": "bearer",
"authSecret": "upstream-secret",
"priority": 10
}'| Field | Required | Description |
|---|---|---|
name | Yes | Display name |
pattern | Yes | Glob pattern matching tool names (e.g., slack_*, *) |
endpoint | Yes | MCP server URL |
authType | No | bearer, api_key, or none (default) |
authSecret | No | Token sent to upstream if authType is set |
priority | No | Higher value = checked first when multiple patterns match |
description | No | Description |
Fetch tools from a provider
curl https://<your-gateway-url>/api/v1/admin/tool-providers/<id>/tools \
-H "Authorization: Bearer <admin-jwt>"Provider Access Control
Access rules control which users and agents can invoke which tools on which providers.
Create an access rule
# Allow a specific user to access a provider
curl -X POST https://<your-gateway-url>/api/v1/admin/provider-access \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"subjectType": "user",
"subjectId": "user-123",
"providerId": "slack-provider-id",
"action": "allow"
}'
# Require confirmation for dangerous tools
curl -X POST https://<your-gateway-url>/api/v1/admin/provider-access \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"subjectType": "agent",
"subjectId": "agent-abc",
"providerId": "files-provider-id",
"action": "require_confirmation",
"toolPattern": "delete_*",
"riskLevel": "critical"
}'
# Deny a user from a sensitive provider
curl -X POST https://<your-gateway-url>/api/v1/admin/provider-access \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"subjectType": "user",
"subjectId": "user-456",
"providerId": "finance-provider-id",
"action": "deny"
}'Rule fields:
| Field | Required | Description |
|---|---|---|
subjectType | Yes | user or agent |
subjectId | Yes | User ID or agent ID |
providerId | Yes | Tool provider ID, or * for all providers |
action | Yes | allow, deny, or require_confirmation |
toolPattern | No | Glob pattern for tool names (default: *) |
riskLevel | No | low, medium, high, or critical |
Set agent rules atomically
Replace all access rules for an agent in one request:
curl -X PUT https://<your-gateway-url>/api/v1/admin/provider-access/agent/<agent-id> \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"rules": [
{ "providerId": "slack-provider-id", "action": "allow" },
{ "providerId": "files-provider-id", "action": "require_confirmation", "toolPattern": "delete_*", "riskLevel": "critical" }
]
}'Policy evaluation
Test a policy before deploying:
curl -X POST https://<your-gateway-url>/api/v1/admin/provider-access/evaluate \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"userId": "user-123",
"providerId": "slack-provider-id",
"toolName": "slack_send_message",
"agentId": "agent-abc"
}'
# Returns: { "action": "allow|deny|require_confirmation", "risk": "low|...", "matchedRule": {...} }Evaluation order
- User-level deny rules
- User-level allow rules
- Agent-level deny rules
- Agent-level allow rules
- Wildcard provider rules (deny, then allow)
- No match → denied by default
Credential Provider Setup
Credential Providers define how each service credential type works. Users store credentials against these providers; agents receive them as injected headers.
api_key provider
curl -X POST https://<your-gateway-url>/api/v1/credential-providers \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Stripe",
"serviceType": "stripe",
"authType": "api_key",
"description": "Stripe payment API"
}'oauth2 provider
curl -X POST https://<your-gateway-url>/api/v1/credential-providers \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Google",
"serviceType": "google",
"authType": "oauth2",
"config": {
"clientId": "your-client-id",
"clientSecret": "your-client-secret",
"scopes": ["openid", "email", "https://www.googleapis.com/auth/calendar"]
}
}'jwt provider
curl -X POST https://<your-gateway-url>/api/v1/credential-providers \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{
"name": "Internal API",
"serviceType": "internal_api",
"authType": "jwt"
}'Supported auth types
| Type | Use case |
|---|---|
api_key | API keys (Stripe, OpenAI, etc.) |
oauth2 | OAuth2 providers (Google, GitHub, Slack, etc.) |
jwt | Service tokens and JWTs |
basic | Username/password credentials |
Multi-Tenancy
All resources can be scoped to a tenantId. Users and agents in different tenants are fully isolated — they cannot see or access each other's agents, credentials, or providers.
admin— can manage all tenants; passtenantIdin request body to scope operationstenant_adminandagent_creator— automatically pinned to their own tenant
Resources with tenantId: null are global and visible to all tenants.
Audit Logs
Every tool call is recorded with full context.
# Recent logs
curl "https://<your-gateway-url>/api/v1/audit/logs?limit=50" \
-H "Authorization: Bearer <admin-jwt>"
# Filter by agent, user, tool, or status
curl "https://<your-gateway-url>/api/v1/audit/logs?agent_id=abc&status=failed" \
-H "Authorization: Bearer <admin-jwt>"
# Aggregate stats
curl https://<your-gateway-url>/api/v1/audit/stats \
-H "Authorization: Bearer <admin-jwt>"Query parameters: user_id, agent_id, tool_name, status, start_date, end_date, limit, offset
Log entry fields:
| Field | Description |
|---|---|
userId | Authenticated user |
agentId | Agent that made the call |
endUserId | End user the agent was acting on behalf of |
providerId | Tool provider that handled the call |
toolName | Tool invoked |
arguments | Tool call arguments (JSON) |
result | Tool response (JSON) |
status | pending / confirmed / rejected / completed / failed |
duration | Execution time in ms |
confirmedBy | User who approved the confirmation (if applicable) |
Production Checklist
- Set a strong
JWT_SECRET(openssl rand -hex 32) - Generate a
CREDENTIAL_ENCRYPTION_KEY(openssl rand -hex 32) - Use PostgreSQL (
DATABASE_URL=postgres://...) - Change the default admin password immediately after first login
- Set
GATEWAY_PUBLIC_URLfor OAuth callbacks and pairing links - Configure
JWT_EXTERNAL_ISSUERSif using an external IdP - Enable HTTPS via a reverse proxy (nginx, Caddy) or cloud platform
- Set up monitoring for the
/healthendpoint
Admin API Reference
| Endpoint | Method | Description |
|---|---|---|
| Users | ||
/api/v1/admin/users | GET | List users |
/api/v1/admin/users | POST | Create user |
/api/v1/admin/users/:id | GET | Get user |
/api/v1/admin/users/:id | PUT | Update user |
/api/v1/admin/users/:id | DELETE | Delete user |
/api/v1/admin/users/:id/roles | POST | Assign role |
/api/v1/admin/users/:id/roles/:role | DELETE | Remove role |
| Agents | ||
/api/v1/admin/agents | GET | List agents |
/api/v1/admin/agents | POST | Register agent |
/api/v1/admin/agents/:id | GET | Get agent |
/api/v1/admin/agents/:id | PUT | Update agent |
/api/v1/admin/agents/:id | DELETE | Delete agent |
/api/v1/admin/agents/:id/disable | POST | Kill switch — disable |
/api/v1/admin/agents/:id/enable | POST | Re-enable |
/api/v1/admin/agents/:id/regenerate-token | POST | New runtime token |
| API Keys | ||
/api/v1/admin/api-keys | GET | List keys |
/api/v1/admin/api-keys | POST | Create key |
/api/v1/admin/api-keys/:id | DELETE | Revoke key |
| Tool Providers | ||
/api/v1/admin/tool-providers | GET | List providers |
/api/v1/admin/tool-providers | POST | Create provider |
/api/v1/admin/tool-providers/:id | GET | Get provider |
/api/v1/admin/tool-providers/:id | PUT | Update provider |
/api/v1/admin/tool-providers/:id | DELETE | Delete provider |
/api/v1/admin/tool-providers/:id/tools | GET | Fetch tools from MCP server |
| Provider Access | ||
/api/v1/admin/provider-access | GET | List rules |
/api/v1/admin/provider-access | POST | Create rule |
/api/v1/admin/provider-access/:id | GET | Get rule |
/api/v1/admin/provider-access/:id | PUT | Update rule |
/api/v1/admin/provider-access/:id | DELETE | Delete rule |
/api/v1/admin/provider-access/agent/:id | GET | Get agent's rules |
/api/v1/admin/provider-access/agent/:id | PUT | Set agent's rules (atomic) |
/api/v1/admin/provider-access/evaluate | POST | Evaluate policy |
| Credential Providers | ||
/api/v1/credential-providers | GET | List providers |
/api/v1/credential-providers | POST | Create provider |
/api/v1/credential-providers/:id | GET | Get provider |
/api/v1/credential-providers/:id | PUT | Update provider |
/api/v1/credential-providers/:id | DELETE | Delete provider |
/api/v1/credential-providers/by-service/:type | GET | Get by service type |
| Audit | ||
/api/v1/audit/logs | GET | Query logs |
/api/v1/audit/logs/:id | GET | Get log entry |
/api/v1/audit/stats | GET | Aggregate statistics |
| Health | ||
/health | GET | Health check |