---
title: Authentication
---
# Authentication
SMG supports multiple authentication methods for securing access to inference APIs and the control plane, including JWT/OIDC integration, API keys, and role-based access control.
---
## Overview
### :material-key-chain: Multiple Auth Methods
Support for JWT/OIDC, API keys, and worker authentication to fit your deployment model.
### :material-shield-account: Role-Based Access
Admin and user roles control access to control plane vs. data plane APIs.
### :material-office-building: Enterprise SSO
Integrate with Keycloak, Auth0, Azure AD, Okta, and other OIDC providers.
### :material-clipboard-text: Audit Logging
Track all control plane operations for security monitoring and compliance.
---
## Authentication Methods
| Method | Use Case | Configuration |
|--------|----------|---------------|
| **Control plane JWT/OIDC** | Enterprise SSO integration with identity providers (admin routes) | `--jwt-issuer`, `--jwt-audience` |
| **Control plane API keys** | Service accounts and programmatic access (admin routes) | `--control-plane-api-keys` |
| **Data plane API key** | Shared bearer token gating data plane routes and forwarded to workers | `--api-key` |
### When to Use Each Method
- **Control plane JWT/OIDC**: Use for enterprise deployments with existing identity providers (Keycloak, Auth0, Azure AD, Okta). Provides centralized user management and SSO for control plane operations.
- **Control plane API keys**: Use for service-to-service automation against admin endpoints (CI/CD pipelines, tooling). Simpler to set up but requires manual key management.
- **Data plane API key**: Use when you want a single shared secret that both clients (calling chat/completions/responses/etc.) and the gateway → worker hop must present.
---
## JWT/OIDC Authentication
JWT (JSON Web Token) authentication allows integration with OIDC-compliant identity providers for enterprise single sign-on.
### Configuration Options
| Option | Environment Variable | Description |
|--------|---------------------|-------------|
| `--jwt-issuer` | `JWT_ISSUER` | OIDC issuer URL (required for JWT auth) |
| `--jwt-audience` | `JWT_AUDIENCE` | Expected audience claim (required for JWT auth) |
| `--jwt-jwks-uri` | `JWT_JWKS_URI` | Explicit JWKS URI (auto-discovered if not set) |
| `--jwt-role-claim` | - | Claim name containing roles (default: `roles`) |
| `--jwt-role-mapping` | - | Map IDP roles to gateway roles |
### Basic Setup
Enable JWT authentication by providing the issuer and audience:
```bash
smg \
--worker-urls http://worker:8000 \
--jwt-issuer "https://auth.example.com/realms/myrealm" \
--jwt-audience "smg-gateway"
```
### JWKS Discovery
By default, SMG discovers the JWKS (JSON Web Key Set) endpoint automatically via OIDC discovery (`/.well-known/openid-configuration`). You can override this with an explicit JWKS URI:
```bash
smg \
--worker-urls http://worker:8000 \
--jwt-issuer "https://auth.example.com" \
--jwt-audience "smg-gateway" \
--jwt-jwks-uri "https://auth.example.com/.well-known/jwks.json"
```
### Role Mapping
Map identity provider roles to SMG gateway roles:
```bash
smg \
--worker-urls http://worker:8000 \
--jwt-issuer "https://auth.example.com" \
--jwt-audience "smg-gateway" \
--jwt-role-mapping "Gateway.Admin=admin" \
--jwt-role-mapping "Gateway.User=user"
```
**Role Mapping Format**: `idp_role=gateway_role`
| Gateway Role | Permissions |
|--------------|-------------|
| `admin` | Full access to all control plane APIs (workers, WASM modules, tokenizers) |
| `user` | Access to inference/data plane APIs only |
### Supported Claims
SMG extracts roles from the following claims (in order of precedence):
1. Configured `--jwt-role-claim` (default: `roles`)
2. `role` claim
3. `roles` claim
4. `groups` claim
5. `group` claim
If no role is found, the user defaults to the `user` role.
### Supported Algorithms
SMG supports the following JWT signing algorithms:
- **RSA**: RS256, RS384, RS512
- **ECDSA**: ES256, ES384
---
## Identity Provider Setup
### Keycloak
**1. Create a Client**
- Navigate to Clients > Create
- Client ID: `smg-gateway`
- Client Protocol: `openid-connect`
- Access Type: `confidential` or `public`
**2. Configure Mappers**
- Add a mapper of type "User Realm Role"
- Token Claim Name: `roles`
- Add to ID token: Yes
- Add to access token: Yes
```bash
smg \
--worker-urls http://worker:8000 \
--jwt-issuer "https://keycloak.example.com/realms/myrealm" \
--jwt-audience "smg-gateway" \
--jwt-role-mapping "admin=admin" \
--jwt-role-mapping "user=user"
```
### Auth0
**1. Create an API**
- Navigate to Applications > APIs > Create API
- Name: `SMG Gateway`
- Identifier: `https://smg.example.com/api`
**2. Add Roles Action**
```javascript
exports.onExecutePostLogin = async (event, api) => {
const namespace = 'https://smg.example.com';
if (event.authorization) {
api.accessToken.setCustomClaim(
`${namespace}/roles`,
event.authorization.roles
);
}
};
```
```bash
smg \
--worker-urls http://worker:8000 \
--jwt-issuer "https://your-tenant.auth0.com/" \
--jwt-audience "https://smg.example.com/api" \
--jwt-role-claim "https://smg.example.com/roles" \
--jwt-role-mapping "smg-admin=admin" \
--jwt-role-mapping "smg-user=user"
```
### Azure AD / Entra ID
**1. Register an Application**
- Navigate to Azure Portal > App registrations
- Name: `SMG Gateway`
- Configure app roles: `Gateway.Admin`, `Gateway.User`
**2. Expose an API**
- Navigate to Expose an API
- Set Application ID URI: `api://smg-gateway`
```bash
smg \
--worker-urls http://worker:8000 \
--jwt-issuer "https://login.microsoftonline.com/{tenant-id}/v2.0" \
--jwt-audience "api://smg-gateway" \
--jwt-role-mapping "Gateway.Admin=admin" \
--jwt-role-mapping "Gateway.User=user"
```
### Okta
```bash
smg \
--worker-urls http://worker:8000 \
--jwt-issuer "https://your-org.okta.com/oauth2/default" \
--jwt-audience "api://smg" \
--jwt-role-mapping "smg_admins=admin" \
--jwt-role-mapping "smg_users=user"
```
---
## API Key Authentication
API keys provide a simpler authentication method for service accounts and programmatic access.
### Control Plane API Keys
Configure API keys for control plane access:
```bash
smg \
--worker-urls http://worker:8000 \
--control-plane-api-keys "key1:Service Account:admin:sk-your-secret-key-here"
```
**Format**: `id:name:role:key`
| Component | Description |
|-----------|-------------|
| `id` | Unique identifier for the key |
| `name` | Human-readable name/description |
| `role` | Gateway role (`admin` or `user`) |
| `key` | The secret API key value |
### Multiple API Keys
```bash
smg \
--worker-urls http://worker:8000 \
--control-plane-api-keys "admin1:Admin Service:admin:sk-admin-key-12345" \
--control-plane-api-keys "user1:Read Only Service:user:sk-readonly-key-67890"
```
### Environment Variable Configuration
For security, pass API keys via environment variable:
```bash
export CONTROL_PLANE_API_KEYS="admin1:Admin Service:admin:sk-admin-key-12345"
smg --worker-urls http://worker:8000
```
### Using API Keys
Clients authenticate by including the API key in the Authorization header:
```bash
curl -H "Authorization: Bearer sk-admin-key-12345" \
https://smg.example.com/workers
```
### Security Features
- **Hashed Storage**: Keys are SHA-256 hashed immediately; plaintext keys are never stored in memory
- **Constant-Time Comparison**: Key verification uses constant-time comparison to prevent timing attacks
- **Role-Based Access**: Each key is assigned a specific role limiting its permissions
---
## Data Plane API Key (`--api-key`)
The `--api-key` option configures a single bearer token that does two things:
```bash
smg \
--worker-urls http://worker:8000 \
--api-key "shared-secret-key"
```
1. **Gates incoming data plane requests.** The gateway requires every client
request to data plane routes (`/v1/chat/completions`, `/v1/completions`,
`/v1/responses`, `/v1/embeddings`, `/v1/rerank`, `/v1/messages`,
`/v1/realtime/*`, etc.) to present `Authorization: Bearer `.
Requests without a valid token receive `401 Unauthorized`.
2. **Propagates to workers.** When a worker has no per-worker `api_key`, the
gateway forwards this same token to the worker as
`Authorization: Bearer `.
This is useful when:
- Clients and workers share a common token
- Workers require authentication (e.g., deployed with API key protection)
- Using DP-aware scheduling that requires authenticated worker queries
- Workers are behind an authentication proxy
Control plane routes (`/workers`, `/wasm`, `/v1/tokenizers`, etc.) use
their own middleware stack. When `--control-plane-api-keys` or
`--jwt-*` are configured they take over as the admin auth backend
(with role-based access control and audit logging); when neither is
set, admin routes fall back to the same `--api-key` bearer check that
guards the data plane. If you run with **only** `--api-key`, the same
shared secret therefore gates both the data plane and the control
plane — which is rarely what you want in production. See
[Control Plane Auth](../../getting-started/control-plane-auth.md) for
configuring JWT/OIDC or dedicated control-plane keys.
---
## Role-Based Access Control
SMG implements role-based access control (RBAC) with two primary roles:
### Admin Role
Full access to all control plane APIs:
- Worker management (`/workers`, `/workers/{id}`)
- WASM module management (`/wasm/*`)
- Tokenizer configuration
- System administration
### User Role
Access to inference/data plane APIs only:
- Chat completions (`/v1/chat/completions`)
- Completions (`/v1/completions`)
- Embeddings (`/v1/embeddings`)
- Model listing (`/v1/models`)
### Role Assignment
Roles are assigned through:
1. **JWT Claims**: Via `--jwt-role-mapping` configuration
2. **API Key Configuration**: Via the role component in `--control-plane-api-keys`
If no role can be determined, the user defaults to `user` role for safety.
---
## Audit Logging
SMG provides audit logging for control plane operations to support security monitoring and compliance.
### Configuration
Audit logging is **enabled by default** when authentication is configured. To disable:
```bash
smg \
--worker-urls http://worker:8000 \
--jwt-issuer "https://auth.example.com" \
--jwt-audience "smg-gateway" \
--disable-audit-logging
```
### Audit Log Format
Audit events are logged with structured fields:
```json
{
"timestamp": "2024-01-15T10:30:00Z",
"principal": "user@example.com",
"auth_method": "jwt",
"role": "admin",
"method": "POST",
"path": "/workers",
"resource": "worker-123",
"outcome": "success",
"request_id": "req-abc-123"
}
```
### Audit Event Fields
| Field | Description |
|-------|-------------|
| `timestamp` | ISO 8601 timestamp of the event |
| `principal` | User ID, email, or API key ID |
| `auth_method` | Authentication method (`jwt`, `api_key`) |
| `role` | Role of the principal (`admin`, `user`) |
| `method` | HTTP method (GET, POST, DELETE, etc.) |
| `path` | Request path |
| `resource` | Resource being accessed (if applicable) |
| `outcome` | Result (`success`, `denied`) |
| `request_id` | Correlation ID for request tracing |
### Viewing Audit Logs
```bash
# Filter for audit logs
RUST_LOG=smg::audit=info smg ...
# Or view in combined logs
kubectl logs -n inference -l app=smg | grep "control_plane_audit"
```
---
## Production Configuration
A production setup combining JWT and API key authentication:
```bash
smg \
--worker-urls http://worker1:8000 http://worker2:8000 \
--host 0.0.0.0 \
--port 443 \
--tls-cert-path /etc/certs/server.crt \
--tls-key-path /etc/certs/server.key \
--jwt-issuer "https://auth.example.com/realms/production" \
--jwt-audience "smg-gateway" \
--jwt-role-mapping "Gateway.Admin=admin" \
--jwt-role-mapping "Gateway.User=user" \
--control-plane-api-keys "ci-cd:CI/CD Pipeline:admin:${CI_CD_API_KEY}" \
--control-plane-api-keys "monitoring:Prometheus:user:${MONITORING_API_KEY}"
```
---
## Kubernetes Deployment
### Secret for API Keys
```yaml
apiVersion: v1
kind: Secret
metadata:
name: smg-auth
namespace: inference
type: Opaque
stringData:
CONTROL_PLANE_API_KEYS: "admin1:Admin:admin:sk-secret-key"
```
### ConfigMap for JWT Configuration
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: smg-config
namespace: inference
data:
JWT_ISSUER: "https://auth.example.com/realms/production"
JWT_AUDIENCE: "smg-gateway"
```
### Deployment
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: smg
namespace: inference
spec:
template:
spec:
containers:
- name: smg
image: smg:latest
envFrom:
- configMapRef:
name: smg-config
- secretRef:
name: smg-auth
args:
- --service-discovery
- --selector
- app=sglang-worker
- --jwt-role-mapping
- "Gateway.Admin=admin"
- --jwt-role-mapping
- "Gateway.User=user"
```
---
## Troubleshooting
### JWT Validation Failures
**Symptom**: `Invalid JWT` or `Token validation failed` errors
**Solutions**:
1. Verify issuer URL matches exactly (including trailing slash):
```bash
curl https://auth.example.com/.well-known/openid-configuration
```
2. Verify audience claim matches your configuration:
```bash
echo "YOUR_JWT" | cut -d. -f2 | base64 -d | jq .
```
3. Check clock synchronization (JWT validation uses time-based claims)
4. Verify JWKS endpoint is accessible from the SMG pod
### API Key Not Working
**Symptom**: `Invalid authentication token` errors
**Solutions**:
1. Verify key format is correct: `id:name:role:key`
2. Check for special characters that may need escaping
3. Ensure the Authorization header format is correct: `Bearer `
### Role Mapping Issues
**Symptom**: Users getting wrong permissions
**Solutions**:
1. Check which claim contains roles in your JWT
2. Verify role mapping syntax: `idp_role=gateway_role`
3. Check if role claim name needs to be specified with `--jwt-role-claim`
---
## Security Best Practices
### :material-shield-lock: Use HTTPS
Always enable TLS for the gateway in production.
### :material-key-change: Rotate Keys
Regularly rotate API keys and use short-lived JWT tokens.
### :material-account-lock: Least Privilege
Assign `user` role by default, `admin` only when needed.
### :material-clipboard-text: Enable Auditing
Keep audit logs for security monitoring and compliance.
---
## What's Next?
### :material-traffic-light: Rate Limiting
Protect against overload and abuse.
[Rate Limiting →](../reliability/rate-limiting.md)
### :material-shield-check: High Availability
Deploy SMG in a highly available configuration.
[High Availability →](../architecture/high-availability.md)
### :material-chart-box: Metrics Reference
Monitor authentication metrics.
[Metrics Reference →](../../reference/metrics.md)