> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ai-coustics.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticate Apps

> Authenticate the SDK with a license key on trusted servers, or with short-lived JWTs minted from your backend on untrusted clients.

The SDK authenticates with our backend before it enhances audio. How you supply that credential depends on where the SDK runs. There are two approaches, and most users only need the first.

* **Server-side authentication (SDK key).** Embed your SDK key directly in a trusted environment you control. This is the simple path and all most users need to get started.
* **Client-side authentication (token minting).** When the SDK runs on untrusted clients (browsers, mobile, end-user devices), mint short-lived JWT tokens from your backend and hand those to the client, so the long-lived SDK key never leaves your servers.

<CardGroup cols={2}>
  <Card title="Use the SDK key directly" icon="key">
    The SDK runs in a trusted environment you control, such as your own servers or backend. The key stays in a place clients cannot reach. [Jump to the SDK key setup.](#server-side-authentication)
  </Card>

  <Card title="Use short-lived JWT tokens" icon="user-lock">
    The SDK runs on untrusted clients you do not control. Mint tokens from your backend so the SDK key never ships to the client. [Jump to token minting.](#client-side-authentication)
  </Card>
</CardGroup>

## Server-side authentication

For trusted, server-side environments, an SDK key is all you need to get started.

### Get an SDK License

Self-service SDK Keys can be generated on the [developer platform](https://developers.ai-coustics.com/).
These keys are configured to authorize with our backend and collect telemetry.

Pass the key straight to the processor exactly as the [Quickstart](/models/get-started/sdk-quickstart) shows. Because the key stays on a backend clients cannot reach, there is nothing else to do. If your SDK runs anywhere a client could read it, use the token minting approach below instead.

## Client-side authentication

Anything you ship to a client can be extracted. A license key baked into a browser bundle or edge binary is one `strings` command away from leaking. So don't ship it. Keep your SDK license on your backend, use it to mint short-lived JWTs, and hand those to clients instead. A JWT drops in exactly where a license key would, and you can swap it for a fresh one before it expires without recreating the processor or reloading the model.

<Info title="Requires SDK 0.19.0 (Python binding 2.3.0) or newer">
  JWT-form license keys and `update_bearer_token()` were introduced in [SDK 0.19.0](/changelog), which ships in the Python `aic-sdk` binding from version 2.3.0 onward.
</Info>

<Steps>
  <Step title="Decode API key from SDK license">
    Self-service SDK Keys can be generated on the [developer platform](https://developers.ai-coustics.com). This key stays on your **backend**, where clients never see it.

    The credential the platform gives you is a signed token of the form `<payload>.<signature>`, where the payload is base64-encoded JSON. Decode that payload once at startup to read the `api_key` field inside it:

    ```python theme={null}
    import base64, json, os

    raw = os.environ["AIC_SDK_LICENSE"]          # signed "<payload>.<signature>" from the platform
    payload = raw.split(".")[0]                  # the first segment is base64-encoded JSON
    api_key = json.loads(base64.b64decode(payload))["api_key"]
    # payload shape: {"user": "user_...", "version": "2", "api_key": "..."}
    ```

    `raw` is the license key the SDK accepts directly, exactly as the [Quickstart](/models/get-started/sdk-quickstart) passes it to `aic.Processor(...)`; don't try to decode it before handing it to the SDK. The inner `api_key` is what the token endpoint expects. In this tutorial the client never touches either one; it only ever sees the JWT you mint below, so reach for `api_key` here and leave `raw` on the backend.

    <Info title="Telemetry">
      These keys are configured to authorize with our backend and collect usage telemetry.
    </Info>
  </Step>

  <Step title="Mint a token on your backend">
    Exchange your API key for a short-lived JWT by calling the token endpoint. Run this server-side so the credential never reaches the client, then return the token to your app over your own API.

    ```python theme={null}
    import requests

    TOKEN_ENDPOINT = "https://api.ai-coustics.io/v1/sdk/tokens"

    def mint_token(api_key: str) -> str:
        """Exchange the API key for a short-lived JWT (~1 hour TTL)."""
        response = requests.post(
            TOKEN_ENDPOINT,
            auth=(api_key, ""),  # HTTP Basic: api_key as username, empty password
            timeout=10,
        )
        response.raise_for_status()
        return response.json()["token"]
    ```
  </Step>

  <Step title="Initialize the SDK with the token">
    Pass the JWT in place of the license key.

    ```python theme={null}
    import aic_sdk as aic

    model_path = aic.Model.download("quail-vf-2.1-l-16khz", "./models")
    model = aic.Model.from_file(model_path)
    config = aic.ProcessorConfig.optimal(model, num_channels=2)

    # The JWT goes exactly where a license key would.
    processor = aic.Processor(model, mint_token(api_key), config)
    processor_context = processor.get_processor_context()
    ```

    <Info title="Initialize with a token, not a plain license key">
      Creating the processor with a minted JWT is what makes the in-place refresh in the next step possible. `update_bearer_token()` only swaps a token when both the originally configured key and the new one are JWTs. If you initialize with a plain license key instead, the swap leaves the existing token in place and raises `TokenUnsupportedError`.
    </Info>
  </Step>

  <Step title="Refresh before the token expires">
    Tokens currently last about an hour, but it could change in the future. Each token tells you when it expires: the `exp` claim inside the JWT, mirrored by the `expires_at` field the token endpoint returns. Derive your refresh time from it and swap the new token in a little before it passes with `update_bearer_token()` on the processor context. There is no need to recreate the processor or reload the model, and the call is safe to make while audio is processing.

    ```python theme={null}
    import base64, json, time

    REFRESH_MARGIN = 300  # swap the token in 5 minutes before it expires

    def token_expiry(token: str) -> int:
        """Read the JWT's `exp` claim (Unix seconds)."""
        payload = token.split(".")[1]                 # the JWT payload segment
        payload += "=" * (-len(payload) % 4)          # restore base64url padding
        return json.loads(base64.urlsafe_b64decode(payload))["exp"]

    # Run this on a background thread; each token's own expiry sets the next wait.
    while True:
        token = mint_token(api_key)
        processor_context.update_bearer_token(token)
        time.sleep(max(0, token_expiry(token) - time.time() - REFRESH_MARGIN))
    ```

    <Info title="What happens if a token lapses">
      If a token expires before you swap in a fresh one, processing raises `LicenseExpiredError`. Mint a new token and retry; the proactive refresh above keeps you clear of this. The only case where enhancement actually stops is a revoked or otherwise unauthorized key, which surfaces as `EnhancementNotAllowedError`. Even then the SDK fails soft: the audio passes through unprocessed and the algorithmic delay is preserved, so the stream is never interrupted. Bypassed audio is tracked by the `usage.disallowed` and `processor.bypass` metrics (learn more on the [Observability](/models/get-started/opentelemetry) page).
    </Info>
  </Step>

  <Step title="Find out more">
    <CardGroup cols={2}>
      <Card title="SDK Quickstart" icon="code" href="/models/get-started/sdk-quickstart">
        Real-time speech enhancement with the SDK in your preferred language.
      </Card>

      <Card title="Developer Platform" icon="key" href="https://developers.ai-coustics.com">
        Generate SDK license keys and explore the SDK playground.
      </Card>

      <Card title="Telemetry" icon="signal-stream" href="/reference/concepts/sdk-telemetry">
        What the SDK reports back and how authorization works.
      </Card>

      <Card title="Python SDK Examples" icon="github" href="https://github.com/ai-coustics/aic-sdk-py/tree/main/examples">
        More examples, including real-time processing and analysis.
      </Card>
    </CardGroup>
  </Step>
</Steps>
