{"record":{"id":"3d27113884c65379","repo":"OpenNHP/opennhp","slug":"unexpected-signing-method-v","errorCode":null,"errorMessage":"unexpected signing method: %v","messagePattern":"unexpected signing method: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/server/kbs/resource/resource.go","lineNumber":254,"sourceCode":"\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\n\ttoken, err := jwt.Parse(tokenString, func(token *jwt.Token) (any, error) {\n\t\t// Check signing method\n\t\tif _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {\n\t\t\treturn nil, fmt.Errorf(\"unexpected signing method: %v\", token.Header[\"alg\"])\n\t\t}\n\t\treturn publicKey, nil\n\t})\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn token, nil\n}\n","sourceCodeStart":236,"sourceCodeEnd":265,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/server/kbs/resource/resource.go#L236-L265","documentation":"During jwt.Parse, the keyfunc verifies the token's alg header is an ECDSA signing method; anything else (RS256, HS256, none) returns 'unexpected signing method: %v'. This prevents algorithm-confusion attacks where a token signed with a weaker or different algorithm is presented while the server holds an ECDSA key.","triggerScenarios":"VerifyJWT receives a token whose header alg is not ES256-family ECDSA — e.g. RS256 tokens from an OIDC provider, HS256 tokens, or alg:none tokens — and jwt.Parse invokes the keyfunc.","commonSituations":"Client misconfigured to sign with RSA or HMAC instead of ES256; token issued by a generic auth service rather than the KBS attestation flow; crafted alg-confusion token from a probing client; library defaults changed between versions.","solutions":["Fix the client to sign with ES256 (ECDSA P-256), matching the embedded P-256 JWK.","Check the token's alg header offline to see what was actually used.","Reject or route non-ECDSA tokens to the appropriate verification path instead of VerifyJWT.","Ensure no client library fallback silently switches algorithms (explicitly set SigningMethodES256).","If RS256 is expected from some clients, embed/use the matching RSA key rather than ECDSA in the keyfunc."],"exampleFix":"// client side before: defaulting to another method\ntoken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)\n// after\ntoken := jwt.NewWithClaims(jwt.SigningMethodES256, claims)\ns, err := token.SignedString(ecdsaPrivateKey)","handlingStrategy":"validation","validationCode":"func algIsECDSA(token string) bool {\n\tparts := strings.Split(token, \".\")\n\tif len(parts) != 3 { return false }\n\thdr, err := base64.RawURLEncoding.DecodeString(parts[0])\n\tif err != nil { return false }\n\tvar h struct{ Alg string `json:\"alg\"` }\n\tif json.Unmarshal(hdr, &h) != nil { return false }\n\treturn strings.HasPrefix(h.Alg, \"ES\")\n}","typeGuard":null,"tryCatchPattern":"token, err := VerifyJWT(rawToken)\nif err != nil && strings.Contains(err.Error(), \"unexpected signing method\") {\n\t// wrong algorithm / possible alg-confusion: return 401, do not retry\n}","preventionTips":["Explicitly pin SigningMethodES256 on the client signer.","Never accept tokens from issuers using other algorithms in this endpoint.","Keep the keyfunc allowlist strict (ECDSA only).","Test with a deliberately wrong-alg token to confirm rejection.","Update client keys, not algorithms, when rotating credentials."],"tags":["jwt","security","algorithm-confusion","authentication"],"backgroundTag":"unsupported-operation","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"}