# Security Best Practices for Grok Production Deployments

> Secure your chenyme/grok2api production deployment with best practices. Learn to implement short-lived JWT tokens, AES-256-GCM encryption, and hardened configuration for robust security.

- Repository: [Chenyme/grok2api](https://github.com/chenyme/grok2api)
- Tags: best-practices
- Published: 2026-08-09

---

**Implement short-lived JWT tokens signed with rotated HMAC secrets, AES-256-GCM encryption for stored credentials, and hardened configuration flags such as `secureCookies` and `swaggerEnabled` to secure the chenyme/grok2api service in production.**

The chenyme/grok2api repository provides a robust security foundation built on JWT access tokens, opaque refresh tokens, and AES-256-GCM encryption. Understanding how to configure these primitives for production workloads is essential to protect admin sessions and sensitive OAuth credentials from unauthorized access.

## Core Security Architecture

Grok2API’s security model is built around three core primitives implemented in the `backend/internal/infra/security` package:

- **JWT Access Token** – Short-lived tokens signed with HMAC-SHA256 using the configured `jwtSecret`. These carry `adminId` and `sessionId` claims and are created via `CreateAccessToken` in [`backend/internal/infra/security/token.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/infra/security/token.go).
- **Opaque Refresh Token** – Cryptographically random tokens generated by `NewOpaqueToken` (32-byte random values) that provide long-lived refresh capabilities without containing parseable claims.
- **AES-256-GCM Cipher** – Authenticated encryption for stored OAuth credentials, implemented in [`backend/internal/infra/security/cipher.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/infra/security/cipher.go) using a 32-byte Base64-encoded key.

All secrets are supplied via environment variables mapped to the configuration file ([`config.example.yaml`](https://github.com/chenyme/grok2api/blob/main/config.example.yaml)), with strict validation enforcing minimum lengths (32-character JWT secret, 32-byte encryption key).

## Production Hardening Guidelines

### Secret Management

Store `jwtSecret` and `credentialEncryptionKey` in a dedicated secrets manager (e.g., HashiCorp Vault, AWS Secrets Manager, or Kubernetes Secrets) and inject them as environment variables. Rotate these secrets periodically; the `NewTokenService` function accepts the current secret, meaning old tokens will fail verification after rotation while new sessions use the updated key.

### Transport and Session Security

Terminate TLS at a reverse proxy (Nginx, Traefik, or cloud load balancer) and set `auth.secureCookies: true` in production to prevent cookie leakage over unencrypted connections. This flag is located in the authentication configuration section and defaults to `false` for local development.

### Network Exposure and Documentation

Disable the built-in Swagger UI by ensuring `swaggerEnabled: false` in production configurations. The documentation endpoint increases attack surface and should only be enabled on trusted internal networks. Bind the server to specific interfaces using `server.listen` rather than `0.0.0.0` when possible.

### Token Lifetime Configuration

Configure `accessTokenTTL` to a short duration (default 15 minutes) to minimize the window of compromise. Set `refreshTokenTTL` (default 720 hours) based on your risk tolerance, and ensure your logout implementation revokes refresh tokens explicitly to prevent replay attacks.

### Database and Runtime Store Security

Replace SQLite with **PostgreSQL** for production deployments by setting `database.driver: postgres` and providing a DSN via the `GROK2API_DATABASE_URL` environment variable. Enable TLS for database connections. For multi-instance deployments, switch from in-memory to **Redis** (`runtimeStore.driver: redis`) and enable TLS via `runtimeStore.redis.tls` to protect session data in transit.

### Auditing and Instance Isolation

Enable audit buffering (`audit.bufferSize`) and enforce ledger mode (`audit.ledgerMode: enforce`) to ensure all administrative actions are logged. When scaling with `deployment.replicas > 1`, assign unique `instanceID` values and a shared `clusterID` across all nodes, enabling `sharedMedia: true` for consistent media handling while maintaining centralized audit logs forwarded to a SIEM.

### Container Security

Run the service as a non-root user inside the container, mounting only required volumes (`/data/backend.db`, `/data/media`). Apply least-privilege network policies and set sensible timeouts (`server.readTimeout`, `server.requestTimeout`) to mitigate slowloris attacks.

## Implementation Examples

### Creating Short-Lived Access Tokens

```go
import (
    "time"
    "github.com/chenyme/grok2api/backend/internal/infra/security"
)

func generateAdminToken(svc *security.TokenService, adminID, sessionID uint64) (string, error) {
    // Short-lived token – 15 min is the default in config.
    token, expires, err := svc.CreateAccessToken(adminID, sessionID, 15*time.Minute)
    if err != nil {
        return "", err
    }
    fmt.Printf("Token valid until %s\n", expires.UTC())
    return token, nil
}

```

*Source*: [`backend/internal/infra/security/token.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/infra/security/token.go)

### Generating Cryptographically Random Refresh Tokens

```go
refresh, err := security.NewOpaqueToken(32) // 32-byte random token
if err != nil {
    log.Fatalf("failed to generate refresh token: %v", err)
}
fmt.Println("Refresh token:", refresh)

```

*Source*: [`backend/internal/infra/security/token.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/infra/security/token.go)

### Encrypting Credentials at Rest

```go
cipher, err := security.NewCipher(os.Getenv("CRED_ENC_KEY")) // Base64-encoded 32-byte key
if err != nil {
    log.Fatalf("cipher init: %v", err)
}
encrypted, err := cipher.Encrypt("my-secret-oauth-token")
if err != nil {
    log.Fatalf("encryption error: %v", err)
}
fmt.Println("Encrypted credential:", encrypted)

```

*Source*: [`backend/internal/infra/security/cipher.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/infra/security/cipher.go)

### Validating Tokens in HTTP Middleware

```go
func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        raw := r.Header.Get("Authorization")
        id, err := tokenService.ParseAccessToken(strings.TrimPrefix(raw, "Bearer "))
        if err != nil {
            http.Error(w, "invalid token", http.StatusUnauthorized)
            return
        }
        // Store identity in context for downstream handlers
        ctx := context.WithValue(r.Context(), "adminID", id.AdminID)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

```

*Source*: [`backend/internal/infra/security/token.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/infra/security/token.go)

## Critical Configuration Files

- **[`backend/internal/infra/security/token.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/infra/security/token.go)** – JWT access token generation, opaque token creation, and parsing logic.
- **[`backend/internal/infra/security/cipher.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/infra/security/cipher.go)** – AES-256-GCM implementation for credential encryption.
- **[`config.example.yaml`](https://github.com/chenyme/grok2api/blob/main/config.example.yaml)** – Reference configuration marking required secrets (`jwtSecret`, `credentialEncryptionKey`) and production flags (`secureCookies`, `swaggerEnabled`).
- **[`backend/internal/transport/http/system/handler.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/transport/http/system/handler.go)** – HTTP server initialization applying timeouts and TLS enforcement.
- **[`backend/internal/app/startup.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/app/startup.go)** – Service initialization wiring token services, cipher, database, and Redis based on configuration.

## Summary

- **Rotate secrets regularly**: Store `jwtSecret` and `credentialEncryptionKey` in external secrets managers and rotate them periodically, accepting that existing access tokens will invalidate immediately while refresh tokens expire naturally.
- **Enforce TLS everywhere**: Enable `secureCookies` and terminate TLS at the edge, ensuring all traffic to the `server.listen` address is encrypted.
- **Minimize attack surface**: Disable `swaggerEnabled`, use short `accessTokenTTL` values, and run containers as non-root users.
- **Use production-grade storage**: Deploy PostgreSQL with TLS and Redis with TLS for multi-instance clusters rather than SQLite or in-memory stores.
- **Enable audit enforcement**: Set `audit.ledgerMode: enforce` and forward logs to centralized monitoring systems to maintain non-repudiation of administrative actions.

## Frequently Asked Questions

### How long should access tokens and refresh tokens be configured for production?

Keep `accessTokenTTL` short (default 15 minutes) to limit the window of compromise, while using a bounded `refreshTokenTTL` (default 720 hours) with explicit revocation on logout. These values are configurable in the settings and should be tightened based on your organization's risk tolerance and session management requirements.

### What encryption standard does Grok2API use for storing OAuth credentials?

The system uses **AES-256-GCM** as implemented in [`backend/internal/infra/security/cipher.go`](https://github.com/chenyme/grok2api/blob/main/backend/internal/infra/security/cipher.go), requiring a 32-byte Base64-encoded `credentialEncryptionKey`. This provides authenticated encryption ensuring both confidentiality and integrity of stored secrets at rest.

### Is it safe to enable the Swagger UI in production?

No. The configuration flag `swaggerEnabled` defaults to `false` and should remain disabled in production environments. Enabling it exposes API documentation and testing endpoints that increase attack surface; restrict it to trusted internal development networks only.

### How do I handle secret rotation for JWT signing keys?

Store the `jwtSecret` in a secrets manager and rotate it periodically. After rotation, instantiate `NewTokenService` with the updated secret; new tokens will be signed with the fresh key while existing tokens fail verification. Existing refresh tokens remain valid until their `refreshTokenTTL` expires or until explicit revocation on logout forces re-authentication with the new secret.