> ## Documentation Index
> Fetch the complete documentation index at: https://eurusys-6c0957fa.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> How the SDK authenticates without ever holding your API secret — the token signer model.

MBKYC uses a **split-secret** authentication model: the SDK holds only the **non-secret API key ID**, while the **secret** stays wherever you choose to keep it (normally your backend). The SDK delegates JWT signing to a callback you provide — the **token signer**.

<Info>
  The SDK **never** receives, stores, or transmits your API secret. This means a compromised device or browser cannot leak it.
</Info>

## The JWT

When the SDK needs to authenticate (device registration and handshake), it builds a JWT:

```
header:  { "alg": "HS256", "typ": "JWT" }
payload: { "key_id": "<your API key ID>", "fingerprint": "<device fingerprint>" }
```

It then computes the **signing input** — `base64url(header) + "." + base64url(payload)` — and hands those bytes to your token signer. Your signer computes `HMAC-SHA256(signingInput, keySecret)` and returns the raw signature. The SDK assembles the final `header.payload.signature` and sends it in the `x-auth-key: Bearer <JWT>` header.

```mermaid theme={null}
sequenceDiagram
    participant SDK
    participant Signer as Token signer (your backend)
    participant VG as Validation Gateway
    SDK->>SDK: build header.payload
    SDK->>Signer: signingInput (header.payload bytes)
    Signer->>Signer: HMAC-SHA256(input, keySecret)
    Signer-->>SDK: raw signature
    SDK->>VG: request with Bearer header.payload.signature
    VG->>VG: look up key_id → verify signature with stored secret
```

The backend looks up the `key_id`, confirms the key is active, and verifies the signature with its stored copy of the secret. A revoked key fails here.

## Implementing the signer

The signer is the same idea in every SDK — receive bytes, return a signature.

<Tabs>
  <Tab title="TypeScript">
    ```ts theme={null}
    const tokenSigner = {
      async sign(signingInput: Uint8Array): Promise<Uint8Array> {
        const res = await fetch('/api/mbkyc/sign', { method: 'POST', body: signingInput });
        return new Uint8Array(await res.arrayBuffer());
      },
    };
    ```
  </Tab>

  <Tab title="Kotlin / Java">
    ```kotlin theme={null}
    val signer = TokenSignerHandler { signingInput -> myBackend.hmacSha256(signingInput) }
    ```
  </Tab>

  <Tab title="C#">
    ```csharp theme={null}
    class MySigner : ITokenSigner {
      public Task<byte[]> SignAsync(byte[] signingInput, CancellationToken ct)
        => myBackend.HmacSha256Async(signingInput, ct);
    }
    ```
  </Tab>

  <Tab title="C">
    ```c theme={null}
    static void on_sign(void* ud, const uint8_t* input, uintptr_t len,
                        MBKYC_SignResponseCallback cb, void* cb_ud) {
        uint8_t sig[32]; /* HMAC-SHA256(input, len) -> sig */
        MBKYC_SignResult r = { .kind = MBKYC_SIGN_RESULT_KIND_SUCCESS,
                               .signature = sig, .signature_len = sizeof(sig) };
        cb(cb_ud, r);
    }
    ```
  </Tab>
</Tabs>

### Server-side signing endpoint

Your `/api/mbkyc/sign` endpoint holds the secret and does the HMAC. In Node:

```js theme={null}
import { createHmac } from 'node:crypto';

app.post('/api/mbkyc/sign', express.raw({ type: '*/*' }), (req, res) => {
  const signature = createHmac('sha256', process.env.MBKYC_KEY_SECRET)
    .update(req.body)        // the raw signingInput bytes
    .digest();
  res.type('application/octet-stream').send(signature);
});
```

<Warning>
  Authenticate and rate-limit your signing endpoint. It is effectively a delegated capability to authenticate as your organization — treat it like any other privileged internal API. It should only ever sign inputs for sessions your own application initiated.
</Warning>

## Other headers

The SDK also sends:

* `x-sdk-id: <sdk>/<version>` (e.g. `kotlin/0.7.0`) — identifies the SDK build.
* Any `extraHeaders` you configured (max 5) — for example, headers your proxy or gateway requires to admit the request.
