crowdsecurity/crowdsec · error

missing scenarios list in login request for TLS auth: %w

Error message

missing scenarios list in login request for TLS auth: %w

What it means

In TLS auth the login request body must contain a 'scenarios' list (used for license/usage tracking even though certs do the real auth). ShouldBindJSON failed — body empty, malformed JSON, or wrong content-type — so authTLS wraps it as 'missing scenarios list in login request for TLS auth'.

Source

Thrown at pkg/apiserver/middlewares/v1/jwt.go:117

	} else if err != nil {
		return nil, fmt.Errorf("while selecting machine entry for %s: %w", ret.machineID, err)
	} else {
		if ret.clientMachine.AuthType != types.TlsAuthType {
			return nil, fmt.Errorf("machine %s attempted to auth with TLS cert but it is configured to use %s", ret.machineID, ret.clientMachine.AuthType)
		}

		ret.machineID = ret.clientMachine.MachineId
	}

	loginInput := struct {
		Scenarios []string `json:"scenarios"`
	}{
		Scenarios: []string{},
	}

	err = c.ShouldBindJSON(&loginInput)
	if err != nil {
		return nil, fmt.Errorf("missing scenarios list in login request for TLS auth: %w", err)
	}

	ret.scenariosInput = loginInput.Scenarios

	return &ret, nil
}

func (j *JWT) authPlain(c *gin.Context) (*authInput, error) {
	var (
		loginInput models.WatcherAuthRequest
		err        error
	)

	ctx := c.Request.Context()

	ret := authInput{}

	if err = c.ShouldBindJSON(&loginInput); err != nil {

View on GitHub (pinned to 909b515798)

Solutions

  1. Send a valid JSON body, e.g. {"scenarios":[]}, with Content-Type: application/json when logging in via TLS
  2. Upgrade the crowdsec agent/bouncer to a version that sends scenarios on TLS login
  3. Test with: curl --cert ... --key ... -H 'Content-Type: application/json' -d '{"scenarios":[]}' https://lapi:8080/api/v1/watchers/login','If you control a custom client, always include the scenarios key (empty list is acceptable)

Example fix

// before
curl -sk --cert client.pem --key client.key -X POST https://lapi:8080/api/v1/watchers/login
// after
curl -sk --cert client.pem --key client.key -H 'Content-Type: application/json' -d '{"scenarios":[]}' -X POST https://lapi:8080/api/v1/watchers/login
Defensive patterns

Strategy: validation

Validate before calling

// validate the TLS login payload before sending
body := map[string][]string{"scenarios": {}}
data, _ := json.Marshal(body)
if !json.Valid(data) {
    return errors.New("invalid TLS login body")
}
req.Header.Set("Content-Type", "application/json")

Try / catch

resp, err := http.Do(tlsLoginReq)
if err != nil || (resp != nil && resp.StatusCode == http.StatusBadRequest) {
    return fmt.Errorf("TLS login rejected, ensure body is {\"scenarios\":[]} with JSON content-type: %w", err)
}

Prevention

When it happens

Trigger: Authenticator -> authTLS: a mTLS client POSTs /api/v1/watchers/login without a JSON body, with invalid JSON, or without Content-Type: application/json; c.ShouldBindJSON returns a binding error which is wrapped.

Common situations: Hand-rolled scripts curling the login endpoint with no body; old/patched agent versions that omit the scenarios field; proxy stripping request bodies; testing with 'curl -X POST' and no -d.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/1bb719f04cba9106. Report an issue: GitHub.