Security Best Practices for Grok Production Deployments
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 carryadminIdandsessionIdclaims and are created viaCreateAccessTokeninbackend/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.gousing a 32-byte Base64-encoded key.
All secrets are supplied via environment variables mapped to the configuration file (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
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
Generating Cryptographically Random Refresh Tokens
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
Encrypting Credentials at Rest
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
Validating Tokens in HTTP Middleware
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
Critical Configuration Files
backend/internal/infra/security/token.go– JWT access token generation, opaque token creation, and parsing logic.backend/internal/infra/security/cipher.go– AES-256-GCM implementation for credential encryption.config.example.yaml– Reference configuration marking required secrets (jwtSecret,credentialEncryptionKey) and production flags (secureCookies,swaggerEnabled).backend/internal/transport/http/system/handler.go– HTTP server initialization applying timeouts and TLS enforcement.backend/internal/app/startup.go– Service initialization wiring token services, cipher, database, and Redis based on configuration.
Summary
- Rotate secrets regularly: Store
jwtSecretandcredentialEncryptionKeyin external secrets managers and rotate them periodically, accepting that existing access tokens will invalidate immediately while refresh tokens expire naturally. - Enforce TLS everywhere: Enable
secureCookiesand terminate TLS at the edge, ensuring all traffic to theserver.listenaddress is encrypted. - Minimize attack surface: Disable
swaggerEnabled, use shortaccessTokenTTLvalues, 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: enforceand 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, 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →