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

  1. Issue the token with alg=HS256 signed with the tenant's HMACSecret.
  2. If your issuer only supports asymmetric algorithms, it is incompatible with this endpoint — use a pre-shared HMAC secret.
  3. 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

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


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/4c13a508b2631a0a. Report an issue: GitHub.