OpenNHP/opennhp · error
missing x coordinate in jwk
Error message
missing x coordinate in jwk
What it means
The embedded JWK must contain the ECDSA public key's 'x' coordinate as a base64url string; if it is absent or not a string, VerifyJWT returns 'missing x coordinate in jwk'. Together with 'y' it reconstructs the ECDSA P-256 public key used to verify the token signature.
Solutions
- Ensure the client embeds a complete EC2/ECDSA JWK with both 'x' and 'y' base64url (unpadded) coordinates.
- Check the embedded key is P-256 ECDSA; RSA or Ed25519 JWKs will not have x/y.
- Inspect the header: `echo <jwk-b64> | base64 -d | jq .jwk` to see which members exist.
- Fix any code that re-serializes the header and changes types (e.g. numbers instead of strings).
- Regenerate the token with the reference KBS client library if hand-rolled signing is incomplete.
Example fix
// before: incomplete JWK header
{"alg":"ES256","jwk":{"kty":"EC","crv":"P-256"}}
// after: full EC2 JWK with coordinates
{"alg":"ES256","jwk":{"kty":"EC","crv":"P-256","x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4","y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM"}} Defensive patterns
Strategy: validation
Validate before calling
func jwkHasXY(jwk map[string]any) bool {
x, xok := jwk["x"].(string)
y, yok := jwk["y"].(string)
return xok && yok && x != "" && y != ""
} Try / catch
token, err := VerifyJWT(rawToken)
if err != nil && strings.Contains(err.Error(), "missing x coordinate") {
// reject token: embedded JWK incomplete; return 401
} Prevention
- Embed complete EC2 JWKs (kty, crv, x, y).
- Only use ECDSA P-256 keys for this flow.
- Assert JWK completeness in client tests before shipping.
- Never hand-assemble JOSE headers.
- Regenerate tokens after changing key types.
When it happens
Trigger: The jwk header object exists but lacks the 'x' member, or 'x' is present with a non-string JSON type (number, object). Called from GetResource during token verification.
Common situations: Client hand-builds the JWK header and forgets x/y; a different key type (RSA/OKP) is embedded whose JWK uses 'n'/'e' or 'k' instead of x/y; JSON marshaling coerced the coordinate into a non-string type.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- missing y coordinate in jwk
- missing or invalid jwk in header
- invalid x coordinate
- invalid y coordinate
- JWT signing key is not initialized
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/c6fc092296448a4f.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/server/kbs/resource/resource.go:228
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 {
return nil, fmt.Errorf("invalid y coordinate: %w", err)
}
publicKey := &ecdsa.PublicKey{
Curve: elliptic.P256(),
X: new(big.Int).SetBytes(xBytes),View on GitHub (pinned to 6e04ca5ff0)