# @l7mp/stunner-auth-lib

A library to generate ICE configuration and TURN credentials for the [STUNner Kubernetes ingress
gateway for WebRTC](https://github.com/l7mp/stunner).

```javascript
const auth = require('@l7mp/stunner-auth-lib');

var credentials = auth.getStunnerCredentials({
    auth_type: 'longterm',
    secret: 'my-shared-secret',
    duration: 24*60*60,  // credentials valid for one day
});
```

## Installation

Install from NPM.

```console
npm install @l7mp/stunner-auth-lib
```

## Usage 

<!-- This library simplifies generating STUN/TURN credentials and ICE server configuration for accessing -->
<!-- the [STUNner Kubernetes ingress gateway for WebRTC ](https://github.com/l7mp/stunner) from WebRTC -->
<!-- clients. -->

The intended use is to ease the generation of STUN/TURN credentials and ICE server configuration
stanza in the WebRTC application server. The application server can send these back to the WebRTC
clients during the WebSocket/JSON call setup process. Clients can then use the STUN/TURN
credentials and ICE server configuration received from the application server to authenticate with
STUNner, in order to reach the WebRTC media plane deployed into Kubernetes behind STUNner.

The library will automatically parse the current STUNner configuration from the Kubernetes control
plane if available. Otherwise, it falls back to taking configuration from environment variables.

![STUNner authentication architecture](/stunner_auth_lib_arch.svg)

### Configuration

The library depends on a valid STUNner configuration for generating STUN/TURN credentials, which is
typically generated by the [STUNner Kubernetes Gateway
Operator](https://github.com/l7mp/stunner-gateway-operator). The STUNner configuration is rendered
into a [Kubernetes
ConfigMap](https://github.com/l7mp/stunner-gateway-operator/README.md#configure-the-operator),
which is then picked up by the [STUNner dataplane](https://github.com/l7mp/stunner) to ingest
WebRTC media into the Kubernetes cluster. Suppose that this ConfigMap is named `stunnerd-config`
(this is the default name). The below Kubernetes pod template snippet shows how to map this
configuration into your WebRTC application server.

``` yaml
...
spec:
  containers:
    - name: <my-application-server>
      image: <my-application-server-image>
      ...
      env:
        - name: STUNNER_CONFIG_FILENAME
          value: "/etc/stunnerd/stunnerd.conf"
      volumeMounts:
        - name: stunnerd-config-volume
          mountPath: /etc/stunnerd
          readOnly: true
  ...
  volumes:
    - name: stunnerd-config-volume
      configMap:
        name: stunnerd-config
...
```

From this point, the STUNner configuration, as actually existing in the `stunnerd-config`
ConfigMap, will be mapped into the application server pod's filesystem under the path
`/etc/stunnerd/stunnerd.conf` and the full path will be available in the `STUNNER_CONFIG_FILENAME`
environment variable.  The library will pick up this configuration and use it to generate the
STUN/TURN credentials and full ICE server configurations necessary to reach STUNner. 

Every time you change the STUNner configuration through the [Kubernetes Gateway
API](https://github.com/l7mp/stunner-gateway-operator/README.md#configure-the-operator), the new
configuration will be immediately mapped into the filesystem of your application server. When
called, the library will re-parse the active configuration from the filesystem and the new settings
will immediately take effect: new client requests will receive up-to-date STUN/TURN
credentials. 

If no valid configuration file is found, the library falls back to the [standalone
mode](README.md#fallback-to-standalone-mode).

### Generating ICE configuration

The recommended usage is generating the [ICE
configuration](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer) along with the
STUNner credentials in a single step and sending it back the WebRTC clients during call setup.

* Generate a full [ICE configuration
  object](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer) on
  the [WebRTC application server](https://bloggeek.me/webrtc-server).

  ```javascript
  const auth = require('@l7mp/stunner-auth-lib');
  ...
  var ICE_config = auth.getIceConfig();
  console.log(ICE_config);
  ```

  Output:

  ```javascript
  {
    iceServers: [
      {
        url: 'turn:1.2.3.4:3478?transport=udp',
        username: 'my-user',
        credential: 'my-password'
      }
    ],
    iceTransportPolicy: 'relay'
  }
  ```

* Send the generated ICE configuration back to the clients during the WebSocket/JSON call setup process
  (e.g., during user registration) and use this configuration in the clients to initialize the WebRTC
  [`PeerConnection`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection).
  
  ```javascript
  var ICE_config = ...; // read ICE configuration from the WebSocket/JSON connection 
  var pc = new RTCPeerConnection(ICE_config);
  ```

You can override the path to the STUNner configuration file (and other options) when calling the
function.

```javascript
var ICE_config = auth.getIceConfig({config_file: <MY_STUNNER_CONFIG_FILENAME>});
```

### Generating STUN/TURN credentials

Alternatively, you can simply generate a new STUN/TURN long-term credentials that you can use for
authenticating with STUNner.

```javascript
var cred = auth.getStunnerCredentials({
    duration: 24 * 60 * 60,  // lifetime the longterm credential is effective
});
console.log(`STUNner credentials: ${cred.username} / ${cred.credential}`);
```

Output:
```
STUNner credentials: 1652118264 / nRU+Iz2ENeP2Y3sDXzSRsFRDs8s=
```

### Fallback to standalone mode

Some may favor running STUNner in the [standalone mode](https://github.com/l7mp/stunner) in order
to be able to manually customize the STUNner dataplane instead of relying on the operator to render
the configuration. The library automatically falls back to using the standalone mode when no
configuration file is available under the path specified by the `STUNNER_CONFIG_FILENAME`
environment variable. For this, the application server needs to have access to the following
environment variables.

* `STUNNER_PUBLIC_ADDR` (no default, must be
  [customized](https://github.com/l7mp/stunner#learning-the-external-ip-and-port)): STUNner public
  IP address.
* `STUNNER_PUBLIC_PORT` (default: 3478): STUNner public port.
* `STUNNER_REALM` (default: `stunner.l7mp.io`): STUN/TURN realm.
* `STUNNER_AUTH_TYPE` (default: `plaintext`): [STUNner authentication
  mode]((https://github.com/l7mp/stunner/tree/main/doc/AUTH.md)); either `plaintext` or `longterm`.
* `STUNNER_USERNAME` (default: `user`):
  [username](https://www.rfc-editor.org/rfc/rfc8489.html#section-14.3) for `plaintext`
  authentication.
* `STUNNER_PASSWORD` (default: `pass`): password for `plaintext` authentication.
* `STUNNER_SHARED_SECRET` (default: `secret`): the shared secret for `longterm` authentication.

For most configuration parameters the library specifies sane defaults, which can be overridden by
the environment variables (i.e., the STUNner configuration), which can in turn be further
overridden in the function arguments specified on the library calls.

The below code will generate a full [ICE configuration
  object](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer) in the fallback mode using
  the specified overrides.
```javascript
const auth = require('@l7mp/stunner-auth-lib');
...
var ICE_config = auth.getIceConfig({
  address: '1.2.3.4',            // ovveride STUNNER_PUBLIC_ADDR
  port: 3478,                    // ovveride STUNNER_PUBLIC_PORT
  auth_type: 'plaintext',        // override STUNNER_AUTH_TYPE
  username: 'my-user',           // override STUNNER_USERNAME
  password: 'my-password',       // override STUNNER_PASSWORD
  ice_transport_policy: 'relay', // override STUNNER_ICE_TRANSPORT_POLICY
});
console.log(ICE_config);
```
The below will generate a new set of STUN/TURN long-term credentials, again using manual overrides.
```javascript
var cred = auth.getStunnerCredentials({
    auth_type: 'longterm',   // override STUNNER_AUTH_TYPE
    secret: 'my-secret',     // override STUNNER_SHARED_SECRET
    duration: 24 * 60 * 60,  // lifetime the longterm credential is effective
});
console.log(`STUNner credentials: ${cred.username} / ${cred.credential}`);
```

Output:
```
STUNner credentials: 1652118264 / nRU+Iz2ENeP2Y3sDXzSRsFRDs8s=
```

Note that all manual overrides are available in the default mode as well.

### Caveats

* In order for the library to be able to read the STUNner configuration, the corresponding
  ConfigMap (i.e., `stunnerd-config`) and the application server must live in the same Kubernetes
  namespace (Kubernetes does not allow a ConfigMap to be mapped into a pod that exists in a
  different namespace). See the [STUNner
  examples](https://github.com/l7mp/stunner/examples/README.md) on how to configure the [STUNner
  Kubernetes Gateway Operator](https://github.com/l7mp/stunner-gateway-operator) to render the
  configuration into an arbitrary namespace from where your application server can pick it up.

* If you change the STUNner credentials from the Kubernetes Gateway API then active clients, which
  have already received an ICE configuration that is now being rendered invalid by your change,
  will need to go through the authentication process (receive a new ICE configuration, re-request
  TURN permissions again from STUNner, etc.)  again. Otherwise, they will time out on the next TURN
  permission refresh cycle. Currently it is the responsibility of the application server to
  orchestrate this process. As a rule of thumb, try to avoid resetting the authentication settings
  when active users are authenticated with STUNner.

## Help

STUNner development is coordinated in Discord, send
[us](https://github.com/l7mp/stunner/blob/main/AUTHORS) an email to ask an invitation.

## License

Copyright 2021-2022 by its authors. Some rights reserved. See
[AUTHORS](https://github.com/l7mp/stunner/blob/main/AUTHORS).

MIT License - see [LICENSE](/LICENSE) for full text.

## Acknowledgments

Initial code adopted from
[@rojo2/turn-credentials](https://www.npmjs.com/package/@rojo2/turn-credentials).
