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

# Authentication

> API key setup and HMAC-SHA256 request signing for SmartAI Assessment.

## API keys

Every SmartAI Assessment account has two keys:

| Key        | Header                | Where it's used                                         |
| ---------- | --------------------- | ------------------------------------------------------- |
| API key    | `x-api-key`           | Every request — identifies your organisation            |
| Secret key | Used for HMAC signing | Every request — proves the request wasn't tampered with |

<Warning>
  Never expose your secret key in browser code or version control. Set both keys as environment variables on your server only.
</Warning>

```bash theme={null}
ASSESSMENT_API_KEY=VFN_TEST_24D67D244DC03E7691654336913EF84B
ASSESSMENT_SECRET_KEY=VFN_SK_TEST_2BA620C5C940D87AF80700B4EE85B4621F516BE8C4F89563
```

### Live vs test environments

The API key prefix determines which environment you're in:

| Prefix      | Environment       | Notes                                   |
| ----------- | ----------------- | --------------------------------------- |
| `VFN_TEST_` | Test / staging    | No real emails sent, safe to experiment |
| `VFN_LIVE_` | Live / production | Real candidate emails, full proctoring  |

***

## HMAC-SHA256 signing

The Backend SDK signs every request automatically. You never need to do this manually. This section is for reference only.

### Signature construction

```
payload = "METHOD:PATH:TIMESTAMP:SORTED_BODY_JSON"

Examples:
  GET:/api/v1/webhook/events:1717200000000:
  POST:/api/v1/sessions:1717200000000:{"users":[{"email":"a@b.com","name":"A"}]}
```

Rules:

* Body keys sorted **alphabetically** (nested keys too)
* Empty body → empty string (not `{}`)
* Timestamp is **Unix milliseconds** as a string

### Headers sent on every request

```
x-api-key:   VFN_TEST_24D67D244DC03E7691654336913EF84B
x-signature: <hmac-sha256-hex-digest>
x-timestamp: 1717200000000
```

### Signing reference

<CodeGroup>
  ```typescript Node.js theme={null}
  import crypto from 'crypto';

  function buildSignature(
    method: string,
    path: string,
    body: object | null,
    secretKey: string
  ): { signature: string; timestamp: string } {
    const timestamp = Date.now().toString();

    const sortedBody = body
      ? JSON.stringify(body, Object.keys(body).sort())
      : '';

    const payload = `${method}:${path}:${timestamp}:${sortedBody}`;

    const signature = crypto
      .createHmac('sha256', secretKey)
      .update(payload)
      .digest('hex');

    return { signature, timestamp };
  }
  ```

  ```python Python theme={null}
  import hashlib
  import hmac
  import json
  import time

  def build_signature(method, path, body, secret_key):
      timestamp = str(int(time.time() * 1000))

      sorted_body = (
          json.dumps(body, sort_keys=True, separators=(",", ":"))
          if body else ""
      )

      payload = f"{method}:{path}:{timestamp}:{sorted_body}"

      signature = hmac.new(
          secret_key.encode(),
          payload.encode(),
          hashlib.sha256,
      ).hexdigest()

      return {"signature": signature, "timestamp": timestamp}
  ```
</CodeGroup>

### Timestamp window

| Environment | Window     |
| ----------- | ---------- |
| Production  | 5 minutes  |
| Development | 30 minutes |

Requests outside the window are rejected with `403 Forbidden`.

***

## SDK initialisation

Instantiate once per request (or share a single instance per server process):

<CodeGroup>
  ```typescript Node.js theme={null}
  const AssessmentClient = require('@recordorg/smartai-assessment-backend');

  const client = new AssessmentClient({
    apiKey:    process.env.ASSESSMENT_API_KEY,
    secretKey: process.env.ASSESSMENT_SECRET_KEY,
  });
  ```

  ```python Python theme={null}
  from smartai_assessment_backend import AssessmentClient
  import os

  client = AssessmentClient(
      api_key=os.getenv("ASSESSMENT_API_KEY"),
      secret_key=os.getenv("ASSESSMENT_SECRET_KEY"),
  )
  ```
</CodeGroup>

The SDK reads both keys and attaches the correct headers and HMAC signature to every outgoing request — you do not pass keys to the frontend or to candidates.
