ory/hydra · critical
a secret for signing HMAC-SHA512/256 is expected to be defin
Error message
a secret for signing HMAC-SHA512/256 is expected to be defined, but none were
What it means
HMACSHA strategy Validate collects the global secret plus rotated secrets; if the resulting key list is empty there is no secret to verify HMAC-SHA512/256 signatures with, so it fails before attempting validation. This guards fosite's access token, refresh token, authorize code, and device code validation paths.
Source
Thrown at fosite/token/hmac/hmacsha.go:108
globalSecret, err := c.Config.GetGlobalSecret(ctx)
if err != nil {
return err
}
if len(globalSecret) > 0 {
keys = append(keys, globalSecret)
}
rotatedSecrets, err := c.Config.GetRotatedGlobalSecrets(ctx)
if err != nil {
return err
}
keys = append(keys, rotatedSecrets...)
if len(keys) == 0 {
return errors.New("a secret for signing HMAC-SHA512/256 is expected to be defined, but none were")
}
for _, key := range keys {
if err = c.validate(ctx, key, token); err == nil {
return nil
} else if errors.Is(err, fosite.ErrTokenSignatureMismatch) {
// Continue to the next key. The error will be returned if it is the last key.
} else {
return err
}
}
return err
}
func (c *HMACStrategy) validate(ctx context.Context, secret []byte, token string) error {
if len(secret) < minimumSecretLength {
return errors.Errorf("secret for signing HMAC-SHA512/256 is expected to be 32 byte long, got %d byte", len(secret))View on GitHub (pinned to 4174065ffb)
Solutions
- Configure a non-empty global secret (Hydra: secrets.system with 16+ chars) before constructing the HMAC strategy
- Check your GlobalSecretProvider/GetGlobalSecret implementation returns at least one non-empty secret
- Add rotated secrets via RotatedGlobalSecretsProvider if the primary secret is intentionally absent
Example fix
// before
strategy := hmacsha.NewHMACStrategy(&fosite.Config{GlobalSecret: []byte{}})
// after
strategy := hmacsha.NewHMACStrategy(&fosite.Config{GlobalSecret: []byte("at-least-16-characters!")}) Defensive patterns
Strategy: validation
Validate before calling
if len(c.GlobalSecret) == 0 {
return errors.New("HMAC strategy requires a non-empty global secret (>=16 bytes)")
} Try / catch
if err := strategy.ValidateAccessToken(ctx, token); err != nil {
if strings.Contains(err.Error(), "secret for signing HMAC") {
// configuration error: abort startup, do not retry request
}
} Prevention
- Wire a GetGlobalSecret that always returns 16+ random bytes
- Fail fast at boot if secrets are missing rather than per-request
- Generate secrets with `openssl rand -base64 32`
When it happens
Trigger: Calling ValidateAccessToken / ValidateRefreshToken / ValidateAuthorizeCode / ValidateDeviceCode when the HMAC strategy's GlobalSecret is nil/empty AND no rotated secrets are provided — e.g. GlobalSecretProvider returns an empty byte slice.
Common situations: Fosite configured with an empty GlobalSecret (nil passed to hmacsha.NewHMACStrategy config); a custom GlobalSecretProvider that returns nil, nil; misconfigured secret provider returning empty slice.
Related errors
- secret for signing HMAC-SHA512/256 is expected to be 32 byte
- failed to set token lifespans due to failed client type asse
- Session must be of type JWTSessionContainer but got type: %T
- GetTokenClaims() must not be nil
- server_error
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/8a231253d6f67d2d.
Report an issue: GitHub.