# PIP-25: Token based authentication

* **Status**: Done
* **Author**: [Matteo Merli](https://github.com/merlimat)
* **Pull Request**: [#2888](https://github.com/apache/pulsar/pull/2888)
* **Mailing List discussion**:
* **Release**: 2.3.0


## Motivation

Pulsar has a [pluggable authentication mechanism](http://pulsar.apache.org/docs/en/security-extending/#authentication)
that currently supports 3 auth providers.

 1. TLS certificates
 2. [Athenz](http://www.athenz.io/)
 3. [Basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication)

Each of them has few issues which could be summarized as:

 1. TLS
   * Requires to have multiple key files in both clients and brokers, making it
     difficult to distribute the credentials.
   * The tools to generate keys are hard to use (OpenSSL)
   * It is hard to automate the creation of certificates
   * Manage the Certificate authority certificate is even harder

 2. Athenz
   * Requires additional service to run
   * Also targets authorization which we don't need since we have internal implementation
     for that

 3. Basic auth
   * Very minimal password file based authentication, not really usable when there
     are multiple clients/brokers

To address these issues, this proposal plans to add a new auth provider that uses
[JSON Web Tokens](https://jwt.io/introduction/)
 ([RFC-7519](https://tools.ietf.org/html/rfc7519)).

 The compact representation of a signed JWT is a string that has three
 parts, each separated by a `.`:

```
 eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY
```

The 3 parts are:
 1. **Header**: contains token infos such as the which algorithm is used for
    the signature
 2. **Payload**: Application specific information. Examples are: `subject`
    (user identifier or principal), `expiration`, etc.. Any kind of info
    can be attached when creating a token and used later during the
    validation
 3. **Signature**: Crypto signature that ensures authenticity of the
    token

The main properties of JSON Web Tokens are:
  1. Tokens are created and signed with a secret key
  2. The secret key can either be a single key or a pair of public/private
     keys. If 2 keys are used, the private key is used to generate the
     tokens and the public key can be distributed to all servers to
     perform validation of such tokens.
  3. Each server can validate a token without talking to any external
     service
  4. By adding information in the payload, the tokens can be scoped in
     many ways. eg:
       * Expire time
       * Limited scope by including reference to some resource
       * Restrict to some client IPs
  5. Revocations are not directly supported, but rather need to be
     implemented by maintaining a black-list of revoked tokens

Note: the TCP connection between client and broker is still expected
to be protected by TLS encryption. That is because the token shouldn't
be sent in clear text over the wire.

## Changes

### Token generation

We need to provide tools to allow an administrator to create the secret
key and the tokens for the users.

For example:

```shell
pulsar tokens create --key $SECRET_KEY --subject new-user-id
```

This will generate a new token and print it on console. This will be done
by administrator (or some automated service) and the token will be passed
to client.

Similarly, administrator will be able to create the secret key to
bootstrap the tokens generation:

```shell
pulsar tokens create-secret-key
```

### Client Side

From client library perspective, a new AuthenticationProvider will be
added that will support taking token and pass that directly to broker
on connection. Client plugin will not interpret the token in any form,
rather just treat it as an opaque string.

This will ensure that multiple tokens format can be used if required.

Additionally the `AuthenticationProvider` will allow the application
to pass a `Supplier<String>` to give the opportunity to fetch the
token from some config or secret store.

### Broker side

AuthenticationProvider in Broker will receive the token and validate
that with the secret key.

The secret key will be either provided in `broker.conf` or a special
class implementing `Supplier<String>` will be specified to fetch the
secret key from config or secret store.
