ory/hydra · error
invalid JWK key
Error message
invalid JWK key
What it means
josex.LoadJSONWebKey unmarshals a JSON Web Key from JSON bytes and then validates it with jose.JSONWebKey.Valid(). If the parsed key is structurally incomplete or cryptographically unusable (missing key material, unsupported/absent key type), it returns 'invalid JWK key'. This guards callers from receiving a JWK that would later fail at signing or verification time.
Source
Thrown at oryx/josex/utils.go:36
import (
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"github.com/go-jose/go-jose/v3"
)
// LoadJSONWebKey returns a *jose.JSONWebKey for a given JSON string.
func LoadJSONWebKey(json []byte, pub bool) (*jose.JSONWebKey, error) {
var jwk jose.JSONWebKey
err := jwk.UnmarshalJSON(json)
if err != nil {
return nil, err
}
if !jwk.Valid() {
return nil, errors.New("invalid JWK key")
}
if jwk.IsPublic() != pub {
return nil, errors.New("priv/pub JWK key mismatch")
}
return &jwk, nil
}
// LoadPublicKey loads a public key from PEM/DER/JWK-encoded data.
func LoadPublicKey(data []byte) (interface{}, error) {
input := data
block, _ := pem.Decode(data)
if block != nil {
input = block.Bytes
}
// Try to load SubjectPublicKeyInfo
pub, err0 := x509.ParsePKIXPublicKey(input)View on GitHub (pinned to 4174065ffb)
Solutions
- Regenerate or re-export the key JSON so it is complete for its kty (RSA needs n and e; EC needs crv, x, y; oct needs k), e.g. via josex.GenerateJWK / go-jose MarshalJSON
- Validate the JWK JSON with a linter or by calling jose.JSONWebKey.UnmarshalJSON yourself and inspecting the error for the missing field
- Re-fetch the JWKS from the issuer if the key came from a remote endpoint — the copy may be truncated or stale
- Confirm the variable/secret holding the key JSON was not truncated by env-var length limits or shell escaping
Example fix
// before (incomplete EC JWK)
json := []byte(`{"kty":"EC","crv":"P-256","x":"..."}`) // missing y
key, err := josex.LoadJSONWebKey(json, true)
// after (complete JWK)
json := []byte(`{"kty":"EC","crv":"P-256","x":"...","y":"..."}`)
key, err := josex.LoadJSONWebKey(json, true) Defensive patterns
Strategy: validation
Validate before calling
func validJWKJSON(json []byte) error {
var jwk jose.JSONWebKey
if err := jwk.UnmarshalJSON(json); err != nil {
return fmt.Errorf("unmarshal JWK: %w", err)
}
if !jwk.Valid() {
return errors.New("JWK is structurally invalid (missing key material for its kty)")
}
return nil
}
// call before: if err := validJWKJSON(keyJSON); err != nil { ... } Type guard
func isValidJWK(raw []byte) bool {
var jwk jose.JSONWebKey
if err := jwk.UnmarshalJSON(raw); err != nil {
return false
}
return jwk.Valid()
} Try / catch
key, err := josex.LoadJSONWebKey(json, true)
if err != nil {
switch {
case err.Error() == "invalid JWK key":
return fmt.Errorf("JWK JSON is incomplete or unsupported: %w", err)
case err.Error() == "priv/pub JWK key mismatch":
return fmt.Errorf("expected a public key but got private (or vice versa): %w", err)
default:
return fmt.Errorf("loading JWK: %w", err)
}
} Prevention
- Generate JWK JSON via josex.GenerateJWK or go-jose MarshalJSON instead of hand-writing it
- Check that RSA JWKs contain n and e, EC JWKs contain crv/x/y, and oct JWKs contain a non-empty k
- Beware env-var size limits and shell quoting when storing key JSON in configuration
- When loading from a JWKS endpoint, re-fetch and log the raw entry when validation fails
- Verify the pub flag matches whether the embedded key material is public or private
When it happens
Trigger: Calling LoadJSONWebKey(json, pub) where json unmarshals into a JSONWebKey whose Valid() is false: e.g. JSON missing the required fields for its key type (no kty, no n/e for RSA, no x/y for EC, empty k for oct), malformed base64url key material, or a kty jose-go cannot parse.
Common situations: Hand-edited or truncated JWK files; JWKS fetched from a server whose entry was corrupted or stripped of key material; config/environment variables holding incomplete key JSON; generating JWK JSON with another tool using parameters go-jose does not accept; passing a symmetric 'oct' JWK where an asymmetric one is expected.
Related errors
- square/go-jose: parse error, got '%s', '%s' and '%s'
- square/go-jose: parse error, got '%s', '%s', '%s' and '%s'
- unknown algorithm %s for signing key
- unknown algorithm %s for encryption key
- unsupported key algorithm: %s
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/537509947efa8361.
Report an issue: GitHub.