crowdsecurity/crowdsec · error

tls authentication required

Error message

tls authentication required

What it means

JWT.authTLS handles mTLS client-certificate authentication for LAPI. It returns "tls authentication required" when j.TlsAuth is nil, i.e. the JWT middleware was constructed without TLS auth wired up even though the request arrived via the TLS-auth path. Normally NewJWT sets TlsAuth: &TLSAuth{}, so nil indicates a manually built JWT or a modified construction path.

Source

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

	machineID := claims[MachineIDKey].(string)

	return &models.WatcherAuthRequest{
		MachineID: &machineID,
	}
}

type authInput struct {
	machineID      string
	clientMachine  *ent.Machine
	scenariosInput []string
}

func (j *JWT) authTLS(c *gin.Context) (*authInput, error) {
	ctx := c.Request.Context()
	ret := authInput{}

	if j.TlsAuth == nil {
		err := errors.New("tls authentication required")
		log.Warn(err)

		return nil, err
	}

	extractedCN, err := j.TlsAuth.ValidateCert(c)
	if err != nil {
		log.Warn(err)
		return nil, err
	}

	logger := log.WithField("ip", c.ClientIP())

	ret.machineID = fmt.Sprintf("%s@%s", extractedCN, c.ClientIP())

	ret.clientMachine, err = j.DbClient.Ent.Machine.Query().
		Where(machine.MachineId(ret.machineID)).
		First(ctx)

View on GitHub (pinned to 909b515798)

Solutions

  1. Construct the middleware with NewJWT(dbClient) so TlsAuth is initialized
  2. If embedding, replicate NewJWT's setup: TlsAuth: &TLSAuth{}
  3. Enable client-certificate auth properly in lapi.yaml under api.server.tls and restart crowdsec
  4. Ensure clients not using mTLS fall back to API-key auth and don't hit the TLS path

Example fix

// before
jwtMiddleware := &JWT{DbClient: dbClient}
// after
jwtMiddleware, err := NewJWT(dbClient) // sets TlsAuth: &TLSAuth{}
Defensive patterns

Strategy: validation

Validate before calling

// before relying on mTLS auth, confirm the middleware has TLS auth wired:
if j.TlsAuth == nil {
    return errors.New("TLS auth middleware not initialized; use NewJWT")
}

Try / catch

authInput, err := j.Authenticator(c)
if err != nil {
    log.WithError(err).Warn("authentication failed")
    c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"message": "authentication failed"})
    return
}

Prevention

When it happens

Trigger: A request authenticated via client certificate reaches Authenticator -> authTLS while the JWT struct's TlsAuth field is nil — e.g. JWT built with &JWT{} instead of NewJWT, or code that nils TlsAuth when TLS is disabled but the server still presents/receives a client cert.

Common situations: Custom embedding of crowdsec's LAPI in another binary; config where api.tls is partially set so the server requests a client cert but the middleware lacks TlsAuth; tests constructing JWT{} directly.

Understand the failure class

Related errors


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