fish2018/pansou · error

unexpected signing method

Error message

unexpected signing method

What it means

During jwt.ParseWithClaims the keyfunc checks that the token's alg header is an HMAC signing method; anything else (e.g. RS256, none) is rejected with "unexpected signing method". This prevents algorithm-confusion attacks where a token signed/unsigned with another alg is accepted.

Solutions

  1. Ensure the token was signed with the same HMAC algorithm (HS256) and secret as this validator
  2. Inspect the token header (base64-decode the first segment) to see its alg value
  3. If you must support other algorithms, extend the keyfunc to handle them explicitly — never accept alg=none
  4. Regenerate tokens with the correct signing method after fixing the issuer

Example fix

// before
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
    return nil, errors.New("unexpected signing method")
}
// after (tighter)
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok || token.Header["alg"] != "HS256" {
    return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
Defensive patterns

Strategy: try-catch

Validate before calling

// decode token header client-side
seg := strings.Split(tokenString, ".")[0]
hdr, _ := base64.RawURLEncoding.DecodeString(seg)
// verify alg is HS256 before sending

Try / catch

claims, err := util.ValidateToken(tokenString, secret)
if err != nil && strings.Contains(err.Error(), "unexpected signing method") {
    // token from wrong issuer/algorithm: reject as untrusted
}

Prevention

When it happens

Trigger: Presenting a JWT whose header declares a non-HMAC alg to ValidateToken; a forged token with alg=none; tokens issued by a service using RS/ES algorithms being validated by this HMAC-only code.

Common situations: Migrating between JWT libraries or services with different signing algorithms; an attacker crafting alg=none tokens; copy-pasted tokens from another project.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/4483d5801ec69ef0. Report an issue: GitHub.

Appendix: source

Thrown at util/jwt.go:53

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString([]byte(secret))
}

// ValidateToken 验证JWT token
func ValidateToken(tokenString string, secret string) (*Claims, error) {
	if tokenString == "" {
		return nil, errors.New("token cannot be empty")
	}
	if secret == "" {
		return nil, errors.New("secret cannot be empty")
	}

	claims := &Claims{}

	token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
		// 验证签名算法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.New("unexpected signing method")
		}
		return []byte(secret), nil
	})

	if err != nil {
		return nil, err
	}

	if !token.Valid {
		return nil, errors.New("invalid token")
	}

	return claims, nil
}

View on GitHub (pinned to beaa561337)