Tencent/WeKnora · error
unexpected signing method: %v
Error message
unexpected signing method: %v
What it means
verifyExternalUserJWT in internal/middleware/auth.go:628 rejects tokens whose alg header is not an HMAC method, even though the parser already restricts valid methods to HS256. This is a defense-in-depth check against algorithm-confusion attacks (e.g. RS256/none alg confusion where an attacker supplies a public key as the HMAC secret).
Source
Thrown at internal/middleware/auth.go:628
func verifyExternalUserJWT(tokenString string, tenantID uint64, secret string) (string, error) {
tokenString = strings.TrimSpace(tokenString)
secret = strings.TrimSpace(secret)
if tokenString == "" {
return "", errors.New("missing external user token")
}
if secret == "" {
return "", errors.New("external user token secret is not configured")
}
claims := jwt.MapClaims{}
parser := jwt.NewParser(
jwt.WithAudience("weknora"),
jwt.WithExpirationRequired(),
jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}),
)
token, err := parser.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(secret), nil
})
if err != nil {
return "", err
}
if token == nil || !token.Valid {
return "", errors.New("invalid external user token")
}
exp, err := claims.GetExpirationTime()
if err != nil || exp == nil {
return "", errors.New("missing expiration")
}
if time.Until(exp.Time) > maxExternalUserTokenTTL {
return "", fmt.Errorf("token lifetime exceeds %s", maxExternalUserTokenTTL)
}
if nbf, nbfErr := claims.GetNotBefore(); nbfErr == nil && nbf != nil && time.Now().Before(nbf.Time) {
return "", errors.New("token not yet valid")View on GitHub (pinned to 988cbb0330)
Solutions
- Issue the token with alg=HS256 signed with the tenant's HMACSecret.
- If your issuer only supports asymmetric algorithms, it is incompatible with this endpoint — use a pre-shared HMAC secret.
- Never attempt to bypass by modifying server-side method checks.
Example fix
// before tok := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) // after tok := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) s, _ := tok.SignedString([]byte(hmacSecret))
Defensive patterns
Strategy: try-catch
Validate before calling
parts := strings.Split(token, ".")
if len(parts) == 3 {
hdr, _ := base64.RawURLEncoding.DecodeString(parts[0])
if !strings.Contains(string(hdr), "\"HS256\"") { // re-sign with HS256 first
}
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "unexpected signing method") {
// re-issue the token with jwt.SigningMethodHS256
}
} Prevention
- Pin jwt.SigningMethodHS256 at issuance, matching the server's WithValidMethods.
- Never use asymmetric tokens against HMAC-only endpoints.
- Treat alg-confusion rejections as security signals, not bugs to bypass.
When it happens
Trigger: A signed-token external user presents a JWT whose header alg is anything other than an HMAC method (RS256, ES256, none, etc.); the keyfunc returns this error before a key is used.
Common situations: Client library auto-selecting RS256 because it has a key pair; a token minted by a different service using asymmetric signing; crafted tokens probing for alg confusion.
Related errors
- token lifetime exceeds %s
- join request not found
- failed to retrieve: %s
- opensearch: index not found
- 2201
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/4c13a508b2631a0a.
Report an issue: GitHub.