Authentication using tokens based on JSON Web Tokens

Pulsar supports authenticating clients using security tokens based on JSON Web Tokens (RFC-7519), including all the algorithms that the Java JWT library supports.

A token is a credential associated with a user. The association is done through a “principal” or “role”. In the case of JWT tokens, it typically refers to a subject. You can use a token to identify a Pulsar client and associate it with a subject that is permitted to do specific actions, such as publish messages to a topic or consume messages from a topic. An alternative is to pass a “token supplier” (a function that returns the token when the client library needs one).

The application specifies the token when you create the client instance. The user typically gets the token string from the administrator. The compact representation of a signed JWT is a string that looks like the following:

  1. eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY

Authentication using JWT - 图1note

Always use TLS encryption when connecting to the Pulsar service, because sending a token is equivalent to sending a password over the wire.

Create client certificates

JWT authentication supports two different kinds of keys to generate and validate the tokens:

  • Symmetric: A single secret key.
  • Asymmetric: A key pair, including:
    • a private key to generate tokens.
    • a public key to validate tokens.

Create a secret key

The administrators create the secret key and use it to generate the client tokens. You can also configure this key for brokers to validate the clients.

The output file is generated in the root of your Pulsar installation directory. You can also provide an absolute path for the output file using the command below.

  1. bin/pulsar tokens create-secret-key --output my-secret.key

To generate a base64-encoded private key, enter the following command.

  1. bin/pulsar tokens create-secret-key --output /opt/my-secret.key --base64

Create a key pair

To use asymmetric key encryption, you need to create a pair of keys. The output file is generated in the root of your Pulsar installation directory. You can also provide an absolute path for the output file using the command below.

  1. bin/pulsar tokens create-key-pair --output-private-key my-private.key --output-public-key my-public.key
  • Store my-private.key in a safe location and only the administrators can use this private key to generate new tokens.
  • The public key file my-public.key is distributed to all Pulsar brokers. You can publicly share it without any security concerns.

Generate tokens

  1. Use this command to require the generated token to have a subject fieldset. This command prints the token string on stdout.

    1. bin/pulsar tokens create --secret-key file:///path/to/my-secret.key \
    2. --subject test-user
  2. Create a token by passing the “private” key using the command below:

    1. bin/pulsar tokens create --private-key file:///path/to/my-private.key \
    2. --subject test-user
  3. Create a token with a pre-defined TTL. Then the token is automatically invalidated.

    1. bin/pulsar tokens create --secret-key file:///path/to/my-secret.key \
    2. --subject test-user \
    3. --expiry-time 1y

Authentication using JWT - 图2tip

The token itself does not have any permission associated. You need to enable authorization and assign superusers, and use the bin/pulsar-admin namespaces grant-permission command to grant permissions to the token.

Enable JWT authentication on brokers/proxies

To configure brokers/proxies to authenticate clients using JWT, add the following parameters to the conf/broker.conf and the conf/proxy.conf file. If you use a standalone Pulsar, you need to add these parameters to the conf/standalone.conf file:

  1. # Configuration to enable authentication
  2. authenticationEnabled=true
  3. authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderToken
  4. # Authentication settings of the broker itself. Used when the broker connects to other brokers, or when the proxy connects to brokers, either in same or other clusters
  5. brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationToken
  6. brokerClientAuthenticationParameters={"token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ.9OHgE9ZUDeBTZs7nSMEFIuGNEX18FLR3qvy8mqxSxXw"}
  7. # Either configure the token string or specify to read it from a file. The following three available formats are all valid:
  8. # brokerClientAuthenticationParameters={"token":"your-token-string"}
  9. # brokerClientAuthenticationParameters=token:your-token-string
  10. # brokerClientAuthenticationParameters=file:///path/to/token
  11. # If using secret key (Note: key files must be DER-encoded)
  12. tokenSecretKey=file:///path/to/secret.key
  13. # The key can also be passed inline:
  14. # tokenSecretKey=data:;base64,FLFyW0oLJ2Fi22KKCm21J18mbAdztfSHN/lAT5ucEKU=
  15. # If using public/private (Note: key files must be DER-encoded)
  16. # tokenPublicKey=file:///path/to/public.key

Configure JWT authentication in CLI Tools

Command-line tools like pulsar-admin, pulsar-perf, and pulsar-client use the conf/client.conf config file in a Pulsar installation.

You need to add the following parameters to the conf/client.conf config file to use the JWT authentication with CLI tools of Pulsar:

  1. webServiceUrl=https://broker.example.com:8443/
  2. brokerServiceUrl=pulsar://broker.example.com:6650/
  3. authPlugin=org.apache.pulsar.client.impl.auth.AuthenticationToken
  4. authParams=token:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY

The token string can also be read from a file, for example:

  1. authParams=file:///path/to/token/file

Configure JWT authentication in Pulsar clients

You can use tokens to authenticate the following Pulsar clients.

  • Java
  • Python
  • Go
  • C++
  • C#
  1. PulsarClient client = PulsarClient.builder()
  2. .serviceUrl("pulsar://broker.example.com:6650/")
  3. .authentication(
  4. AuthenticationFactory.token("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY"))
  5. .build();

Similarly, you can also pass a Supplier:

  1. PulsarClient client = PulsarClient.builder()
  2. .serviceUrl("pulsar://broker.example.com:6650/")
  3. .authentication(
  4. AuthenticationFactory.token(() -> {
  5. // Read token from custom source
  6. return readToken();
  7. }))
  8. .build();
  1. from pulsar import Client, AuthenticationToken
  2. client = Client('pulsar://broker.example.com:6650/',
  3. authentication=AuthenticationToken('eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY'))

Alternatively, you can also pass a Supplier:

  1. def read_token():
  2. with open('/path/to/token.txt') as tf:
  3. return tf.read().strip()
  4. client = Client('pulsar://broker.example.com:6650/',
  5. authentication=AuthenticationToken(read_token))
  1. client, err := pulsar.NewClient(pulsar.ClientOptions{
  2. URL: "pulsar://localhost:6650",
  3. Authentication: NewAuthenticationToken("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY"),
  4. })

Similarly, you can also pass a Supplier:

  1. client, err := pulsar.NewClient(pulsar.ClientOptions{
  2. URL: "pulsar://localhost:6650",
  3. Authentication: pulsar.NewAuthenticationTokenSupplier(func () string {
  4. // Read token from custom source
  5. return readToken()
  6. }),
  7. })
  1. #include <pulsar/Client.h>
  2. pulsar::ClientConfiguration config;
  3. config.setAuth(pulsar::AuthToken::createWithToken("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY"));
  4. pulsar::Client client("pulsar://broker.example.com:6650/", config);
  1. var client = PulsarClient.Builder()
  2. .AuthenticateUsingToken("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY")
  3. .Build();