gofiber/fiber · error
decode SHA256 password: %w
Error message
decode SHA256 password: %w
What it means
Returned by parseHashedPassword when a Users value starts with '{SHA256}' but the trailing bytes are not decodable as standard base64. Equivalent to the SHA512 case but expects a 32-byte SHA-256 digest encoded with standard base64 (the Apache '{SHA}' htpasssd style but for SHA-256). Causes startup setup() to fail.
Source
Thrown at middleware/basicauth/config.go:288
case strings.HasPrefix(h, "{SHA512}"):
b, err := base64.StdEncoding.DecodeString(h[len("{SHA512}"):])
if err != nil {
return nil, fmt.Errorf("decode SHA512 password: %w", err)
}
// A digest of the wrong size can never equal a SHA-512 sum, so
// accepting it would silently reject every password for this user.
// Report it instead, which surfaces as a panic at startup.
if len(b) != sha512.Size {
return nil, ErrInvalidSHA512PasswordLength
}
return func(p string) bool {
sum := sha512.Sum512([]byte(p))
return subtle.ConstantTimeCompare(sum[:], b) == 1
}, nil
case strings.HasPrefix(h, "{SHA256}"):
b, err := base64.StdEncoding.DecodeString(h[len("{SHA256}"):])
if err != nil {
return nil, fmt.Errorf("decode SHA256 password: %w", err)
}
if len(b) != sha256.Size {
return nil, ErrInvalidSHA256PasswordLength
}
return func(p string) bool {
sum := sha256.Sum256([]byte(p))
return subtle.ConstantTimeCompare(sum[:], b) == 1
}, nil
default:
b, err := hex.DecodeString(h)
if err != nil || len(b) != sha256.Size {
if b, err = base64.StdEncoding.DecodeString(h); err != nil {
return nil, fmt.Errorf("decode SHA256 password: %w", err)
}
if len(b) != sha256.Size {
return nil, ErrInvalidSHA256PasswordLength
}
}View on GitHub (pinned to 9a4c7e57fe)
Solutions
- Produce the expected encoding: printf '%s' "$PW" | openssl dgst -sha256 -binary | base64, prefix with '{SHA256}'.
- Remove any embedded whitespace/newlines from the digest before storing.
- Use standard base64 (A–Z, a–z, 0–9, +, /, '=' padding); avoid URL-safe or hex.
- Verify decoded length is 32 bytes to avoid the follow-on ErrInvalidSHA256PasswordLength.
Example fix
// before: 'sha256sum' hex output after the prefix
users := map[string]string{"bob": "{SHA256}" + hexDigest}
// after: raw SHA-256 bytes in standard base64
// $ printf '%s' 'hunter2' | openssl dgst -sha256 -binary | base64
users := map[string]string{"bob": "{SHA256}" + b64Digest} Defensive patterns
Strategy: validation
Validate before calling
func validSHA256Entry(v string) error {
const p = "{SHA256}"
if !strings.HasPrefix(v, p) {
return fmt.Errorf("missing %q prefix", p)
}
b, err := base64.StdEncoding.DecodeString(v[len(p):])
if err != nil {
return fmt.Errorf("not standard base64: %w", err)
}
if len(b) != sha256.Size {
return fmt.Errorf("decoded length %d != %d", len(b), sha256.Size)
}
return nil
} Type guard
null
Try / catch
null
Prevention
- Generate digests with: printf '%s' "$PW" | openssl dgst -sha256 -binary | base64.
- Don't feed 'sha256sum' hex output to {SHA256}.
- Preserve trailing '=' padding when copying values.
- Use standard base64 (+, /), not URL-safe (-, _) or hex.
When it happens
Trigger: Users map entry like "{SHA256}" + a hex string, a URL-safe base64 string, a value with truncated padding, or stray whitespace. Also triggered by feeding a digest generated by a tool that defaults to hex (sha256sum) without re-encoding to base64.
Common situations: Running 'echo -n pass | sha256sum' (hex) and pasting after '{SHA256}'; copy/paste dropping '=' padding; YAML/JSON parser stripping trailing '='; using base64 -w0 with URL-safe mode (-e vs -u confusion).
Related errors
- decode SHA512 password: %w
- basicauth: charset must be UTF-8
- decode SHA256 password: invalid length
- failed to base64-decode key: %w
- fiber: keyauth middleware requires a validator function
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/2e507eed61a54cc6.json.
Report an issue: GitHub.