dgraph-io/dgraph · error

couldn't parse signing method from token header: %s

Error message

couldn't parse signing method from token header: %s

What it means

The token's alg header matched a.Algo, but a.SigningMethod is neither *jwt.SigningMethodHMAC nor *jwt.SigningMethodRSA, so the library does not know what key material to return to the verifier (it only supports HMAC symmetric keys and RSA public keys here). This means the SigningMethod field was set to an unsupported type (e.g. ECDSA) or left nil while Algo was set.

Source

Thrown at graphql/authorization/auth.go:407

		// The JWT library supports comparison of `aud` in JWT against a single string. Hence, we
		// disable the `aud` claim verification at the library end using `WithoutAudienceValidation` and
		// use our custom validation function `validateAudience`.
		token, err =
			jwt.ParseWithClaims(jwtStr, &CustomClaims{authMeta: a}, func(token *jwt.Token) (interface{}, error) {
				algo, _ := token.Header["alg"].(string)
				if algo != a.Algo {
					return nil, errors.Errorf("unexpected signing method: Expected %s Found %s",
						a.Algo, algo)
				}

				switch a.SigningMethod.(type) {
				case *jwt.SigningMethodHMAC:
					return []byte(a.VerificationKey), nil
				case *jwt.SigningMethodRSA:
					return a.RSAPublicKey, nil
				}

				return nil, errors.Errorf("couldn't parse signing method from token header: %s", algo)
			})
	}

	if err != nil {
		return nil, errors.Errorf("unable to parse jwt token:%v", err)
	}

	claims, ok := token.Claims.(*CustomClaims)
	if !ok || !token.Valid {
		return nil, errors.Errorf("claims in jwt token is not map claims")
	}

	if err := claims.validateAudience(); err != nil {
		return nil, err
	}
	return claims, nil
}

View on GitHub (pinned to 759e242be6)

Solutions

  1. Set SigningMethod to jwt.SigningMethodHS256 (HMAC) or jwt.SigningMethodRS256/RS384/RS512 (RSA) matching your keys.
  2. If using ECDSA, switch keys to RSA or extend the switch to handle *jwt.SigningMethodECDSA and return the public key.
  3. Ensure SigningMethod is never nil when Algo is set — validate at startup.
  4. Verify VerificationKey (HMAC secret) or RSAPublicKey is populated for the chosen method.
  5. Align a.Algo with the family of SigningMethod (RS256↔RSA, HS256↔HMAC).

Example fix

// before
auth := &authorization.AuthOptions{ Algo: "ES256", VerificationKey: key }
// after
auth := &authorization.AuthOptions{ Algo: "RS256", SigningMethod: jwt.SigningMethodRS256, RSAPublicKey: pubKey }
Defensive patterns

Strategy: validation

Validate before calling

func (a *AuthMeta) validateSigningConfig() error {
    if len(a.JWKUrls) != 0 { return nil }
    switch a.SigningMethod.(type) {
    case *jwt.SigningMethodHMAC:
        if a.VerificationKey == "" { return errors.New("HMAC chosen but VerificationKey empty") }
    case *jwt.SigningMethodRSA:
        if a.RSAPublicKey == nil { return errors.New("RSA chosen but RSAPublicKey empty") }
    default:
        return errors.New("SigningMethod must be HMAC or RSA")
    }
    return nil
}

Type guard

func supportedSigningMethod(m jwt.SigningMethod) bool {
    switch m.(type) {
    case *jwt.SigningMethodHMAC, *jwt.SigningMethodRSA:
        return true
    }
    return false
}

Try / catch

if err := authCfg.validateSigningConfig(); err != nil {
    log.Fatalf("unsupported signing configuration: %v", err)
}

Prevention

When it happens

Trigger: In the static-key keyfunc: algo == a.Algo passes, then the type switch on a.SigningMethod matches neither *jwt.SigningMethodHMAC nor *jwt.SigningMethodRSA (nil or e.g. *jwt.SigningMethodECDSA), so the fallback errors.Errorf fires.

Common situations: AuthOptions.SigningMethod nil because only Algo was set; ECDSA keys used with a library path that only supports HMAC/RSA; SigningMethod assigned via reflection/config of wrong type; copy-paste from an example using a different algorithm family.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/ba2ef72ec92dcfe3. Report an issue: GitHub.