Tencent/WeKnora · critical
failed to generate OIDC state signing key: %v
Error message
failed to generate OIDC state signing key: %v
What it means
OIDC state signing key initialization mirrors the JWT secret path: it uses JWT_SECRET if set, otherwise generates 32 random bytes with crypto/rand. If rand.Read fails, the code panics because OIDC state parameters cannot be signed without a key, breaking CSRF protection for the OIDC flow.
Source
Thrown at internal/utils/oidc_state.go:40
Nonce string `json:"nonce"`
RedirectURI string `json:"redirect_uri,omitempty"`
IssuedAt int64 `json:"iat"`
}
var (
oidcStateSecretOnce sync.Once
oidcStateSecret string
)
func oidcStateSigningKey() string {
oidcStateSecretOnce.Do(func() {
if envSecret := strings.TrimSpace(os.Getenv("JWT_SECRET")); envSecret != "" {
oidcStateSecret = envSecret
return
}
randomBytes := make([]byte, 32)
if _, err := rand.Read(randomBytes); err != nil {
panic(fmt.Sprintf("failed to generate OIDC state signing key: %v", err))
}
oidcStateSecret = base64.StdEncoding.EncodeToString(randomBytes)
})
return oidcStateSecret
}
// SignOIDCState returns a tamper-evident state token: base64url(payload).base64url(hmac).
func SignOIDCState(payload *OIDCStatePayload) (string, error) {
if payload == nil {
return "", errors.New("oidc state payload is required")
}
if strings.TrimSpace(payload.Nonce) == "" {
return "", errors.New("oidc state nonce is required")
}
if strings.TrimSpace(payload.RedirectURI) == "" {
return "", errors.New("oidc state redirect_uri is required")
}
if payload.IssuedAt == 0 {View on GitHub (pinned to 988cbb0330)
Solutions
- Set JWT_SECRET so the env-var branch is taken and rand is never needed
- Adjust the sandbox/seccomp policy to permit getrandom(2) or ensure /dev/urandom exists
- Restart the process — the failure is often transient during early boot
- Provision the key from a file or secret manager instead of generating at runtime
Example fix
// before
randomBytes := make([]byte, 32)
if _, err := rand.Read(randomBytes); err != nil { panic(...) }
// after
# deployment fix
JWT_SECRET=<base64 32-byte secret> # set in environment, skipping rand fallback Defensive patterns
Strategy: fallback
Validate before calling
if strings.TrimSpace(os.Getenv("JWT_SECRET")) == "" {
if _, err := rand.Read(make([]byte, 32)); err != nil {
return fmt.Errorf("cannot obtain entropy for OIDC state key: %w", err)
}
} Type guard
func oidcStateKeyAvailable() bool {
return strings.TrimSpace(os.Getenv("JWT_SECRET")) != ""
} Try / catch
func oidcStateSecretSafe() (s string, err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("oidc state key panicked: %v", r) } }()
return getOIDCStateSecret(), nil
} Prevention
- Set JWT_SECRET wherever OIDC login is enabled
- Permit getrandom(2) in container/sandbox policies
- Provision signing keys via secret manager for deterministic startup
When it happens
Trigger: First use of the OIDC state singleton when JWT_SECRET is unset and the OS entropy source fails (getrandom syscall blocked by seccomp, missing /dev/urandom, early-boot kernel without random ready).
Common situations: Hardened container seccomp profiles blocking getrandom; minimal/embedded runtimes; same root cause as the JWT secret panic — environments where crypto/rand cannot read 32 bytes.
Related errors
- failed to generate JWT secret: %v
- invalid path: %w
- invalid file path: %w
- invalid source path: %w
- zip URL blocked by SSRF check: %v
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/9c1747bb47587401.
Report an issue: GitHub.