OpenNHP/opennhp · error
missing or invalid jwk in header
Error message
missing or invalid jwk in header
What it means
After successful unverified parsing, VerifyJWT requires the JOSE header to carry a 'jwk' object containing the signer's public key; if the header lacks 'jwk' or it is not a JSON object, it returns 'missing or invalid jwk in header'. This scheme expects embedded-JWK (jwk header parameter) authentication as used by KBS/attestation tokens.
Solutions
- Configure the client signer to embed the public key: e.g. in go-jose use jws.WithEmbeddedKey / the 'jwk' header option when signing.
- Verify the client targets the KBS token format (embedded ECDSA P-256 JWK), not a standard OIDC token.
- Inspect the token header with `echo <header-b64> | base64 -d` to confirm the jwk field.
- Update the client library/version if it drops custom headers during signing.
- If tokens come from a different issuer, use the appropriate verification path instead of VerifyJWT.
Example fix
// before: signing without embedded key
token := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
// after: ensure the public key is embedded in the header
// (go-jose style)
signer, _ := jose.NewSigner(jose.SigningKey{Algorithm: jose.ES256, Key: priv},
(&jose.SignerOptions{}).EmbedJWK())
jws, _ := signer.Sign(payload) Defensive patterns
Strategy: validation
Validate before calling
func headerHasJWK(token string) bool {
parts := strings.Split(token, ".")
if len(parts) != 3 { return false }
hdr, err := base64.RawURLEncoding.DecodeString(parts[0])
if err != nil { return false }
var h map[string]any
if json.Unmarshal(hdr, &h) != nil { return false }
_, ok := h["jwk"].(map[string]any)
return ok
} Try / catch
token, err := VerifyJWT(rawToken)
if err != nil && err.Error() == "missing or invalid jwk in header" {
// client did not embed its public key; return 401 with guidance
} Prevention
- Use the signer option that embeds the JWK (e.g. jose EmbedJWK).
- Target the KBS attestation token format specifically.
- Do not substitute OIDC/OAuth tokens for KBS tokens.
- Unit-test token generation to assert the jwk header exists.
- Decode and inspect headers in CI when changing signing libraries.
When it happens
Trigger: VerifyJWT receives a validly-formed JWT whose header has no 'jwk' field, has jwk as a non-object (string/null/array), or the client signs with a server-side key reference instead of embedding the public key.
Common situations: Client library signs tokens without the EmbedJwk option; a generic OIDC/OAuth token (kid-based) is sent where a KBS attestation token is expected; header produced by a different token generator (e.g. plain HS256 token) lacking the jwk parameter.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- failed to parse token
- missing x coordinate in jwk
- missing y coordinate in jwk
- invalid x coordinate
- invalid y coordinate
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/9ab698c8d3814b00.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/server/kbs/resource/resource.go:222
}
ciphertext = gcm.Seal(nil, iv, plaintext, nil)
return ciphertext, iv, nil, nil
}
func VerifyJWT(tokenString string) (*jwt.Token, error) {
// First parse the token without verification to get the header
parser := jwt.NewParser()
unverifiedToken, _, err := parser.ParseUnverified(tokenString, jwt.MapClaims{})
if err != nil {
return nil, fmt.Errorf("failed to parse token: %w", err)
}
// Extract JWK from header
jwkHeader, ok := unverifiedToken.Header["jwk"].(map[string]any)
if !ok {
return nil, fmt.Errorf("missing or invalid jwk in header")
}
// Convert JWK back to ECDSA public key
xStr, ok := jwkHeader["x"].(string)
if !ok {
return nil, fmt.Errorf("missing x coordinate in jwk")
}
yStr, ok := jwkHeader["y"].(string)
if !ok {
return nil, fmt.Errorf("missing y coordinate in jwk")
}
xBytes, err := base64.RawURLEncoding.DecodeString(xStr)
if err != nil {
return nil, fmt.Errorf("invalid x coordinate: %w", err)
}
yBytes, err := base64.RawURLEncoding.DecodeString(yStr)
if err != nil {View on GitHub (pinned to 6e04ca5ff0)