# Authentication

> **API status.** The OneKYC Tenant API is in beta. Endpoints, data formats, and API versions may change. Track documentation updates.

To call the OneKYC API from a server, you need to authenticate. Two mechanisms are supported: HMAC signing for server-to-server interaction (Tenant API) and a JWT token for verification-session access (used by the verification page when the end user opens a link).

## HMAC (server-to-server with the OneKYC API) [#hmac-server-to-server-with-the-name-api]

Server-side requests are signed with HMAC-SHA256. This mechanism proves that the request came from an authorised API key holder.

**Required headers:**

- **Authorization** — `HMAC-SHA256 Credential={key_id}, Signature={signature}`
- **X-Timestamp** — current Unix time (seconds). Requests with clock drift over 5 minutes are rejected (replay protection).

**Signature algorithm:**

1. Build the string to sign (components are joined by a newline `\n`):

   ```
   stringToSign = timestamp + "\n" + method + "\n" + path + "\n" + bodyHash
   ```

   where:
   - `timestamp` — value of the X-Timestamp header (Unix seconds)
   - `method` — HTTP method in upper case (GET, POST, PUT, DELETE, etc.)
   - `path` — full request path with query parameters (for example, `/tenant/v1/kyc/applicants?page=1`)
   - `bodyHash` — SHA256 hash of the request body in hex (empty string for GET requests and other bodyless requests)

2. Compute HMAC-SHA256 using the API key secret:

   ```
   signature = HMAC-SHA256(stringToSign, api_secret)
   ```

   Encode the result in hex (a 64-character string).

3. Build and send the request with the headers above. Example endpoint for creating a verification link:

API operations:

- `POST /v1/kyc/verification-links`

**Example (JavaScript / Node.js):**

```javascript
const crypto = require("crypto");

// 1. Compute bodyHash (SHA256 hash of the request body)
const body = JSON.stringify({ flow_id: "uuid-here" });
const bodyHash = crypto.createHash("sha256").update(body).digest("hex");

// 2. Build the string to sign
const timestamp = Math.floor(Date.now() / 1000).toString();
const method = "POST";
const path = "/tenant/v1/kyc/verification-links";
const stringToSign = `${timestamp}\n${method}\n${path}\n${bodyHash}`;

// 3. Compute the HMAC-SHA256 signature
const apiSecret = "your_api_secret_here";
const signature = crypto
  .createHmac("sha256", apiSecret)
  .update(stringToSign)
  .digest("hex");

// 4. Build the request headers
const headers = {
  "Content-Type": "application/json",
  "X-Timestamp": timestamp,
  Authorization: `HMAC-SHA256 Credential=kyc_test_<your_key_id>, Signature=${signature}`,
};
```

**Example (Go):**

```go
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "strconv"
    "time"
)

// 1. Compute bodyHash (SHA256 hash of the request body)
body := map[string]string{"flow_id": "uuid-here"}
bodyBytes, _ := json.Marshal(body)
hash := sha256.Sum256(bodyBytes)
bodyHash := hex.EncodeToString(hash[:])

// 2. Build the string to sign
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
method := "POST"
path := "/tenant/v1/kyc/verification-links"
stringToSign := fmt.Sprintf("%s\n%s\n%s\n%s", timestamp, method, path, bodyHash)

// 3. Compute the HMAC-SHA256 signature
apiSecret := "your_api_secret_here"
mac := hmac.New(sha256.New, []byte(apiSecret))
mac.Write([]byte(stringToSign))
signature := hex.EncodeToString(mac.Sum(nil))

// 4. Build the request headers
// Authorization: HMAC-SHA256 Credential=kyc_test_<your_key_id>, Signature={signature}
// X-Timestamp: {timestamp}
```

**The API key secret** is shown **once** when you create the key in the admin panel — store it in a secure vault. Keep the secret on the server side; do not ship it to client applications.

**Key formats:**

- **KYC keys:** prefix `kyc_live_` for production, `kyc_test_` for the test environment. Grant access to `/tenant/v1/kyc/` endpoints.
- **KYB keys:** prefix `kyb_live_` for production, `kyb_test_` for the test environment. Grant access to `/tenant/v1/kyb/` endpoints only.

The key secret carries the `sk_` prefix. Keys are created and revoked in the **API keys** section of the admin panel.

**Test and live modes:**

- **Test keys** (`kyc_test_*`, `kyb_test_*`) — for development and testing. No real verifications are run.
- **Live keys** (`kyc_live_*`, `kyb_live_*`) — for production. Process real user verifications.
- Keys are isolated: test keys do not access live data and vice versa.
- KYC keys cannot call KYB endpoints and vice versa — the server returns HTTP 403.

**Scopes:** when you create a key, you select scopes that determine the available operations.

**KYC scopes** (for `kyc_*` keys):

| Scope                | Description                          |
| -------------------- | ------------------------------------ |
| `applicants:read`    | Read applicant data                  |
| `applicants:write`   | Modify and delete applicants         |
| `sessions:create`    | Create verification sessions and create, batch-create, or revoke KYC verification links |
| `verifications:read` | Read verification and AML results    |
| `documents:read`     | Read documents                       |
| `media:read`         | Read media files                     |
| `webhooks:read`      | Read webhook configuration           |
| `webhooks:write`     | Manage webhooks                      |
| `metrics:read`       | Read metrics and analytics           |
| `audit:read`         | Read the audit log                   |
| `verification-links:read`  | Read verification links        |
| `documents:upload`   | Upload documents                     |
| `reviews:read`       | Read the manual review queue, tasks, comments, and reject reasons |
| `reviews:write`      | Assign, decide, comment, priority, and resubmit on KYC review tasks |

**KYB scopes** (for `kyb_*` keys):

| Scope                          | Description                                    |
| ------------------------------ | ---------------------------------------------- |
| `businesses:read`              | Read business data                             |
| `businesses:write`             | Modify business data                           |
| `kyb.sessions:read`            | Read KYB sessions                              |
| `kyb.verification-links:read`  | Read KYB verification links                    |
| `kyb.verification-links:write` | Create and manage KYB verification links       |
| `kyb.documents:read`           | Read KYB documents                             |
| `kyb.media:read`               | Read KYB media files (also required for review document URLs) |
| `kyb.webhooks:read`            | Read KYB webhook configuration                 |
| `kyb.webhooks:write`           | Manage KYB webhooks                            |
| `kyb.metrics:read`             | Read KYB metrics                               |
| `kyb.audit:read`               | Read the KYB audit log                         |
| `kyb.reviews:read`             | Read the KYB manual review queue and tasks      |
| `kyb.reviews:write`            | Assign, decide, comment, priority, and resubmit on KYB review tasks |

Manual review for integrators: [Review tasks](/en/api/review).

Each endpoint requires the matching scope; if access is insufficient, the server returns HTTP 403. Wildcard scopes are supported: `*` (full access) or `applicants:*` (all applicant operations).

## JWT (verification-session access) [#jwt-verification-session-access]

When a verification link is activated, OneKYC issues a short-lived JWT token. The OneKYC verification page uses this token: when the end user opens the link, every API request (fetching session data, uploading documents, executing steps) carries the `Authorization: Bearer <token>` header. The token lifetime is set when you create the link (for example, 600 seconds).

---

**Summary:** server-side integration uses HMAC signing with an API key to call the Tenant API; the end user's verification access uses a JWT token issued when the link is activated. For full endpoint reference, see [Sessions](/en/api/sessions) and [API reference (OpenAPI)](/en/api/api-reference).
