> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/temporalio/temporal/llms.txt
> Use this file to discover all available pages before exploring further.

# Security, Authentication, and Authorization

> Configure authentication, authorization, and encryption for Temporal Server

Temporal Server provides comprehensive security features including mutual TLS, JWT authentication, and role-based authorization.

## Transport Layer Security (TLS)

### Server TLS Configuration

Configure TLS for each service group:

```yaml theme={null}
global:
  tls:
    # Backend service communication (history, matching)
    internode:
      server:
        certFile: "/path/to/internode-cert.pem"
        keyFile: "/path/to/internode-key.pem"
        clientCAFiles:
          - "/path/to/ca-cert.pem"
        requireClientAuth: true
      client:
        serverName: "temporal-internode"
        rootCAFiles:
          - "/path/to/ca-cert.pem"
        disableHostVerification: false
    
    # Frontend service
    frontend:
      server:
        certFile: "/path/to/frontend-cert.pem"
        keyFile: "/path/to/frontend-key.pem"
        clientCAFiles:
          - "/path/to/ca-cert.pem"
        requireClientAuth: true
      client:
        serverName: "temporal-frontend"
        rootCAFiles:
          - "/path/to/ca-cert.pem"
```

### TLS Options

**Server Configuration:**

* `certFile` - Server certificate (PEM format)
* `keyFile` - Private key (PEM format)
* `certData` - Base64 encoded certificate (alternative to file)
* `keyData` - Base64 encoded key (alternative to file)
* `clientCAFiles` - CA certificates for client verification
* `clientCAData` - Base64 encoded CA certificates
* `requireClientAuth` - Enable mutual TLS (mTLS)

**Client Configuration:**

* `serverName` - Expected server name in certificate (for SNI)
* `rootCAFiles` - CA certificates to verify server
* `rootCAData` - Base64 encoded CA certificates
* `disableHostVerification` - Skip hostname verification (not recommended)
* `forceTLS` - Use TLS even without client certificates

### Per-Host TLS Overrides

Different TLS settings for different hostnames:

```yaml theme={null}
global:
  tls:
    frontend:
      server:
        certFile: "/path/to/default-cert.pem"
        keyFile: "/path/to/default-key.pem"
      hostOverrides:
        "temporal.example.com":
          certFile: "/path/to/example-cert.pem"
          keyFile: "/path/to/example-key.pem"
          requireClientAuth: true
        "temporal.internal.local":
          certFile: "/path/to/internal-cert.pem"
          keyFile: "/path/to/internal-key.pem"
          requireClientAuth: false
```

### System Worker TLS

Configure TLS for system workers:

```yaml theme={null}
global:
  tls:
    systemWorker:
      certFile: "/path/to/worker-cert.pem"
      keyFile: "/path/to/worker-key.pem"
      client:
        serverName: "temporal-frontend"
        rootCAFiles:
          - "/path/to/ca-cert.pem"
```

### Remote Cluster TLS

For cross-cluster replication:

```yaml theme={null}
global:
  tls:
    remoteClusters:
      cluster-east:
        client:
          serverName: "temporal-east.example.com"
          rootCAFiles:
            - "/path/to/east-ca.pem"
      cluster-west:
        client:
          serverName: "temporal-west.example.com"
          rootCAFiles:
            - "/path/to/west-ca.pem"
```

### Certificate Expiration Monitoring

```yaml theme={null}
global:
  tls:
    expirationChecks:
      warningWindow: "720h"  # 30 days - log warnings
      errorWindow: "168h"    # 7 days - log errors
      checkInterval: "1h"    # Check every hour
    refreshInterval: "24h"  # Reload certs from disk every 24h
```

Monitor certificate expiration with metrics:

* `certificates_expired` - Number of expired certificates
* `certificates_expiring` - Certificates expiring within warning window

## Authentication

### JWT Authentication

Temporal supports JWT (JSON Web Token) authentication:

```yaml theme={null}
global:
  authorization:
    jwtKeyProvider:
      keySourceURIs:
        - "file:///path/to/public-key.pem"
        - "https://auth.example.com/.well-known/jwks.json"
      refreshInterval: "1h"
```

### Custom Claim Mapper

Implement the `ClaimMapper` interface to extract claims from auth tokens:

```go theme={null}
type ClaimMapper interface {
    GetClaims(authInfo *AuthInfo) (*Claims, error)
}
```

**AuthInfo Structure:**

```go theme={null}
type AuthInfo struct {
    AuthToken     string           // JWT or other token
    TLSSubject    *pkix.Name       // Client certificate subject
    TLSConnection *credentials.TLSInfo
    ExtraData     string           // Additional auth data
    Audience      string           // Target audience
}
```

**Default JWT Claim Mapper:**

The default implementation (`DefaultJWTClaimMapper`) extracts:

* `sub` - Subject identifier
* `aud` - Audience validation
* `exp` - Token expiration
* `iat` - Issued at time
* System and namespace roles from custom claims

### Authorization Headers

Configure custom header names:

```yaml theme={null}
global:
  authorization:
    authHeaderName: "authorization"        # JWT token header
    authExtraHeaderName: "authorization-extras"  # Additional auth data
```

## Authorization

### Role-Based Access Control

Temporal implements role-based authorization with three permission levels:

**System-Level Roles:**

* `Admin` - Full system access, all operations
* `Writer` - Non-admin write operations
* `Reader` - Read-only operations

**Namespace-Level Roles:**

* `Admin` - Full namespace access
* `Writer` - Non-admin operations in namespace
* `Reader` - Read-only operations in namespace

### Authorization Configuration

```yaml theme={null}
global:
  authorization:
    enabled: true
    claimMapper: "default"  # or custom implementation
    authorizer: "default"   # or custom implementation
```

### Default Authorization Rules

The `DefaultAuthorizer` implements these rules:

1. **Health check APIs** - Always allowed (no auth required)
2. **System Admin** - Access all APIs, all namespaces
3. **System Writer** - Non-admin APIs, all namespaces
4. **System Reader** - Read-only APIs, all namespaces
5. **Namespace Admin** - All APIs in their namespaces
6. **Namespace Writer** - Non-admin APIs in their namespaces
7. **Namespace Reader** - Read-only APIs in their namespaces

### API Access Levels

**Cluster-Scoped APIs:**

* Require system-level roles
* Examples: namespace management, cluster operations

**Namespace-Scoped APIs:**

* Require namespace-level or system-level roles
* Examples: workflow operations, visibility queries

### Claims Structure

```go theme={null}
type Claims struct {
    System     Role                // System-level role
    Namespaces map[string]Role     // Namespace roles
    Extensions any                 // Custom extensions
}
```

**Role Values:**

```go theme={null}
const (
    RoleUndefined Role = 0
    RoleReader    Role = 1
    RoleWriter    Role = 2
    RoleAdmin     Role = 4
)
```

### Custom Authorizer

Implement the `Authorizer` interface for custom logic:

```go theme={null}
type Authorizer interface {
    Authorize(ctx context.Context, claims *Claims, target *CallTarget) (Result, error)
}

type CallTarget struct {
    Namespace string  // Target namespace
    APIName   string  // API method name
    Request   any     // Full request object
}

type Result struct {
    Decision Decision  // Allow or Deny
    Reason   string    // Optional reason for denial
}
```

### Cross-Namespace Authorization

For workflows that interact across namespaces:

```yaml theme={null}
global:
  dynamicConfig:
    system.enableCrossNamespaceCommands:
      - value: true
        constraints: {}
```

When enabled, the system authorizes:

* `SignalExternalWorkflowExecution` to different namespace
* `StartChildWorkflowExecution` in different namespace
* `RequestCancelExternalWorkflowExecution` for different namespace

### Authorization Metrics

Monitor authorization:

```plaintext theme={null}
service_authorization_latency      # Authorization check duration
service_errors_unauthorized        # Denied requests
service_errors_authorize_failed    # Authorization errors
```

### Expose Authorization Errors

```yaml theme={null}
global:
  dynamicConfig:
    system.exposeAuthorizerErrors:
      - value: false  # Return generic error
        constraints: {}
```

When `false`, returns generic "Request unauthorized" message. When `true`, includes specific authorization failure details.

## Database Encryption

### At-Rest Encryption

Configure encryption at the database level:

<Tabs>
  <Tab title="Cassandra">
    ```yaml theme={null}
    persistence:
      datastores:
        default:
          cassandra:
            hosts: "cassandra.example.com"
            keyspace: "temporal_encrypted"
            tls:
              enabled: true
              certFile: "/path/to/db-cert.pem"
              keyFile: "/path/to/db-key.pem"
              caFile: "/path/to/db-ca.pem"
              enableHostVerification: true
              serverName: "cassandra.example.com"
    ```
  </Tab>

  <Tab title="PostgreSQL">
    ```yaml theme={null}
    persistence:
      datastores:
        default:
          sql:
            pluginName: "postgres12"
            databaseName: "temporal"
            connectAddr: "postgres.example.com:5432"
            connectProtocol: "tcp"
            connectAttributes:
              sslmode: "verify-full"
              sslcert: "/path/to/client-cert.pem"
              sslkey: "/path/to/client-key.pem"
              sslrootcert: "/path/to/ca-cert.pem"
            tls:
              enabled: true
    ```
  </Tab>

  <Tab title="MySQL">
    ```yaml theme={null}
    persistence:
      datastores:
        default:
          sql:
            pluginName: "mysql8"
            databaseName: "temporal"
            connectAddr: "mysql.example.com:3306"
            connectProtocol: "tcp"
            connectAttributes:
              tls: "custom"
            tls:
              enabled: true
              certFile: "/path/to/client-cert.pem"
              keyFile: "/path/to/client-key.pem"
              caFile: "/path/to/ca-cert.pem"
              enableHostVerification: true
              serverName: "mysql.example.com"
    ```
  </Tab>
</Tabs>

### Payload Encryption

Implement application-level encryption using data converters in SDK clients. Temporal Server stores payloads as opaque bytes.

## Security Best Practices

### 1. Enable mTLS Everywhere

```yaml theme={null}
global:
  tls:
    internode:
      server:
        requireClientAuth: true  # Enforce mTLS
    frontend:
      server:
        requireClientAuth: true
```

### 2. Rotate Certificates Regularly

* Set `refreshInterval` to reload certificates
* Monitor expiration metrics
* Automate certificate renewal (e.g., cert-manager)

### 3. Use Strong JWT Algorithms

Supported algorithms:

* RS256, RS384, RS512 (RSA signatures)
* ES256, ES384, ES512 (ECDSA signatures)
* PS256, PS384, PS512 (RSA-PSS signatures)

Avoid:

* HS256 (symmetric, shared secrets)
* None algorithm

### 4. Implement Least Privilege

* Grant minimum required roles
* Use namespace-scoped roles over system roles
* Separate admin operations to dedicated accounts

### 5. Network Segmentation

* Isolate internode traffic on private network
* Expose frontend only through load balancer
* Use firewall rules to restrict access

### 6. Audit Logging

Enable structured logging to capture:

* Authorization decisions
* Failed authentication attempts
* Admin operations

```yaml theme={null}
log:
  level: "info"
  encoding: "json"
  outputFile: "/var/log/temporal/audit.log"
```

### 7. Rate Limiting

Configure via dynamic config:

```yaml theme={null}
dynamicConfigClient:
  filepath: "config/dynamicconfig/production.yaml"
```

```yaml theme={null}
# production.yaml
frontend.rps:
  - value: 2400
    constraints: {}
frontend.namespaceRPS:
  - value: 1200
    constraints:
      namespace: "production-namespace"
```

### 8. Secure Database Access

* Use dedicated database credentials per Temporal service
* Enable database audit logging
* Restrict database network access
* Use encrypted connections
* Regularly rotate database passwords

### 9. Secrets Management

Store secrets externally:

* Kubernetes Secrets
* HashiCorp Vault
* AWS Secrets Manager
* Azure Key Vault

Mount secrets as files, reference in config:

```yaml theme={null}
global:
  tls:
    frontend:
      server:
        certFile: "/var/run/secrets/tls/cert.pem"
        keyFile: "/var/run/secrets/tls/key.pem"
```

## Troubleshooting

### TLS Handshake Failures

**Symptoms:**

* `x509: certificate signed by unknown authority`
* `x509: certificate is valid for X, not Y`
* `tls: bad certificate`

**Solutions:**

1. Verify CA certificate chain
2. Check `serverName` matches certificate CN/SAN
3. Ensure `requireClientAuth` matches client configuration
4. Validate certificate expiration dates

### Authorization Denied

**Symptoms:**

* `Request unauthorized`
* `service_errors_unauthorized` metrics increasing

**Solutions:**

1. Check JWT signature and expiration
2. Verify audience claim matches expected value
3. Review role mappings in claims
4. Enable `exposeAuthorizerErrors` for debugging (development only)
5. Check authorization metrics with namespace tags

### Certificate Rotation

Temporal reloads certificates based on `refreshInterval`. To force reload, restart the service.

## See Also

* [Monitoring](/operations/monitoring) - Authorization metrics
* [Configuration Reference](https://docs.temporal.io/references/configuration) - Full config options
* [SDK Security](https://docs.temporal.io/security) - Client-side security
