Mutual TLS (mTLS) makes the client present a certificate too; its distinguished name becomes the principal, and no password exists to leak. BookNest's MTLS listener and the controller listener set ssl.client.auth=required, and ssl.principal.mapping.rules=RULE:^.*CN=([^,]+).*$/$1/,DEFAULT shortens CN=booknest-packer,O=BookNest to booknest-packer for ACLs. The broker's own certificate maps to User:broker, a super user, so one name covers the broker on its SCRAM and its certificate connections. The cost is a CA to run: issuing, renewing before expiry (the demo's certificates last 90 days) and revoking, which Kafka 129 does not check by default.
OAuth 2.0 (SASL/OAUTHBEARER) moves identity to a provider such as Keycloak 44,186 , Okta or Microsoft Entra ID. The client obtains a signed JSON Web Token (JWT), usually with the client_credentials grant; the broker checks its signature against the provider's published keys (JWKS), its expiry and audience, and takes the principal from the sub claim. Kafka 4.3 ships both halves (broker configuration from its documentation, not run here):
listener.name.external.oauthbearer.sasl.server.callback.handler.class=\
org.apache.kafka.common.security.oauthbearer.OAuthBearerValidatorCallbackHandler
listener.name.external.oauthbearer.sasl.oauthbearer.jwks.endpoint.url=\
https://login.example.com/realms/booknest/protocol/openid-connect/certs
listener.name.external.oauthbearer.sasl.oauthbearer.expected.audience=booknest-kafkaJava clients name the provider's sasl.oauthbearer.token.endpoint.url, choose sasl.oauthbearer.jwt.retriever.class=org.apache.kafka.common.security.oauthbearer.ClientCredentialsJwtRetriever and give their client ID and secret (sasl.oauthbearer.client.credentials.client.id and .client.secret).
Since Kafka 4.0 the JVM system property org.apache.kafka.sasl.oauthbearer.allowed.urls must list every token and JWKS URL a broker or client may call; it is empty by default, so a configuration from an older guide fails until KAFKA_OPTS sets it. MSK Provisioned Clusters ran the same handshake locally with a token callback, the way MSK IAM and Google's managed Kafka authenticate librdkafka clients.