{"record":{"id":"e3ae0fac3680e3a0","repo":"OpenNHP/opennhp","slug":"missing-y-coordinate-in-jwk","errorCode":null,"errorMessage":"missing y coordinate in jwk","messagePattern":"missing y coordinate in jwk","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/server/kbs/resource/resource.go","lineNumber":232,"sourceCode":"\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),\n\t\tY:     new(big.Int).SetBytes(yBytes),\n\t}\n\n\t// Now verify the token with the extracted public key","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/server/kbs/resource/resource.go#L214-L250","documentation":"Symmetric to the x-coordinate check: if the embedded JWK lacks 'y' or it is not a string, VerifyJWT returns 'missing y coordinate in jwk'. Both coordinates are required to reconstruct the ECDSA P-256 public key for signature verification.","triggerScenarios":"jwk header contains 'x' but not 'y', or 'y' has a non-string JSON type. Reached from GetResource token verification after x passes.","commonSituations":"Partially hand-assembled JWK header; client only serializes x due to a bug or truncation; key material generated for a curve/key type that doesn't use y (e.g. Ed25519).","solutions":["Add the 'y' base64url coordinate to the embedded JWK on the client side.","Verify the signing key is ECDSA P-256; switch client key generation if not.","Inspect the decoded header JWK to confirm which members are present.","Fix serialization code that drops fields after unmarshal/re-marshal.","Use a maintained signing library so the full public JWK is embedded automatically."],"exampleFix":"// before\njwk := map[string]any{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\": xB64}\n// after\njwk := map[string]any{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\": xB64, \"y\": yB64}","handlingStrategy":"validation","validationCode":"func jwkComplete(jwk map[string]any) bool {\n\t_, xok := jwk[\"x\"].(string); _, yok := jwk[\"y\"].(string)\n\treturn xok && yok\n}","typeGuard":null,"tryCatchPattern":"token, err := VerifyJWT(rawToken)\nif err != nil && strings.Contains(err.Error(), \"missing y coordinate\") {\n\t// incomplete JWK: return 401\n}","preventionTips":["Always serialize both coordinates from the same code path.","Use one JWK-building helper to avoid x/y drift.","Keep curve P-256; other types lack y.","Test the full token round-trip in CI.","Avoid post-processing that drops JSON members."],"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"}