{"record":{"id":"c6fc092296448a4f","repo":"OpenNHP/opennhp","slug":"missing-x-coordinate-in-jwk","errorCode":null,"errorMessage":"missing x coordinate in jwk","messagePattern":"missing x coordinate in jwk","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/server/kbs/resource/resource.go","lineNumber":228,"sourceCode":"\nfunc VerifyJWT(tokenString string) (*jwt.Token, error) {\n\t// First parse the token without verification to get the header\n\tparser := jwt.NewParser()\n\tunverifiedToken, _, err := parser.ParseUnverified(tokenString, jwt.MapClaims{})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse token: %w\", err)\n\t}\n\n\t// Extract JWK from header\n\tjwkHeader, ok := unverifiedToken.Header[\"jwk\"].(map[string]any)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"missing or invalid jwk in header\")\n\t}\n\n\t// Convert JWK back to ECDSA public key\n\txStr, ok := jwkHeader[\"x\"].(string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"missing x coordinate in jwk\")\n\t}\n\tyStr, ok := jwkHeader[\"y\"].(string)\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"missing y coordinate in jwk\")\n\t}\n\n\txBytes, err := base64.RawURLEncoding.DecodeString(xStr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid x coordinate: %w\", err)\n\t}\n\tyBytes, err := base64.RawURLEncoding.DecodeString(yStr)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid y coordinate: %w\", err)\n\t}\n\n\tpublicKey := &ecdsa.PublicKey{\n\t\tCurve: elliptic.P256(),\n\t\tX:     new(big.Int).SetBytes(xBytes),","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/server/kbs/resource/resource.go#L210-L246","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: incomplete JWK header\n{\"alg\":\"ES256\",\"jwk\":{\"kty\":\"EC\",\"crv\":\"P-256\"}}\n// after: full EC2 JWK with coordinates\n{\"alg\":\"ES256\",\"jwk\":{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4\",\"y\":\"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM\"}}","handlingStrategy":"validation","validationCode":"func jwkHasXY(jwk map[string]any) bool {\n\tx, xok := jwk[\"x\"].(string)\n\ty, yok := jwk[\"y\"].(string)\n\treturn xok && yok && x != \"\" && y != \"\"\n}","typeGuard":null,"tryCatchPattern":"token, err := VerifyJWT(rawToken)\nif err != nil && strings.Contains(err.Error(), \"missing x coordinate\") {\n\t// reject token: embedded JWK incomplete; return 401\n}","preventionTips":["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."],"tags":["jwt","jwk","ecdsa","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}