dgraph-io/dgraph · error

unexpected signing method in token: %v

Error message

unexpected signing method in token: %v

What it means

The key-lookup callback in jwt.Parse rejects tokens whose header 'alg' does not match the configured ACL algorithm (WorkerConfig.AclJwtAlg.Alg()). This is an algorithm-confusion defense: a token signed with a different (possibly weaker) algorithm must not be accepted. The error includes the token's alg header value.

Source

Thrown at x/jwt_helper.go:36

)

// MaybeKeyToBytes converts the x.Sensitive type into []byte if the type of interface really
// is x.Sensitive. We keep the type x.Sensitive for private and public keys so that it
// doesn't get printed into the logs but the type the JWT library needs is []byte.
func MaybeKeyToBytes(k interface{}) interface{} {
	if kb, ok := k.(Sensitive); ok {
		return []byte(kb)
	}
	return k
}

func ParseJWT(jwtStr string) (jwt.MapClaims, error) {
	token, err := jwt.Parse(jwtStr, func(token *jwt.Token) (interface{}, error) {
		if WorkerConfig.AclJwtAlg == nil {
			return nil, errors.Errorf("ACL is disabled")
		}
		if token.Method.Alg() != WorkerConfig.AclJwtAlg.Alg() {
			return nil, errors.Errorf("unexpected signing method in token: %v", token.Header["alg"])
		}
		return MaybeKeyToBytes(WorkerConfig.AclPublicKey), nil
	})
	if err != nil {
		// This is for backward compatibility in clients
		if errors.Is(err, jwt.ErrTokenExpired) {
			err = errors.Wrap(errTokenExpired, jwt.ErrTokenInvalidClaims.Error())
		}
		return nil, errors.Wrapf(err, "unable to parse jwt token")
	}

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

View on GitHub (pinned to 759e242be6)

Solutions

  1. Re-issue the access JWT signed with the algorithm the server expects (match WorkerConfig.AclJwtAlg).
  2. Align server config: set AclJwtAlg to the algorithm actually used to sign your tokens.
  3. Check the token issuer/pipeline — ensure you are sending the ACL access token, not some other JWT.
  4. Read the alg value in the error message and compare against your signing code's algorithm; fix whichever side is wrong.

Example fix

// before: client signs with RS256 while server expects HS256
alg := jwt.SigningMethodRS256
// after: use the configured algorithm
tok := jwt.NewWithClaims(WorkerConfig.AclJwtAlg, claims)
Defensive patterns

Strategy: validation

Validate before calling

parts := strings.Split(token, ".")
if len(parts) != 3 { return errors.New("malformed jwt") }
hdr, _ := base64.RawURLEncoding.DecodeString(parts[0])
var h struct{ Alg string `json:"alg"` }
json.Unmarshal(hdr, &h)
if h.Alg != WorkerConfig.AclJwtAlg.Alg() {
    return fmt.Errorf("token alg %s does not match configured %s", h.Alg, WorkerConfig.AclJwtAlg.Alg())
}

Type guard

func algMatches(token *jwt.Token) bool {
    return WorkerConfig.AclJwtAlg != nil && token.Method.Alg() == WorkerConfig.AclJwtAlg.Alg()
}

Prevention

When it happens

Trigger: jwt.Parse is given a token whose alg header (e.g. RS256, none, HS256) differs from WorkerConfig.AclJwtAlg.Alg() — e.g. client signs JWTs with the wrong algorithm or a token from a different system is presented.

Common situations: Client side regenerated keys with a different alg after a server upgrade; mixing tokens from a non-ACL system; maliciously crafted tokens probing for algorithm confusion; config where server expects HS256 but clients use RS256.

Related errors


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