
# Authentication

Every request to the Myaza verification and Risk Intelligence APIs (except the public [health check](https://trust.myaza.co/documentation/errors/markdown#health-check)) must be authenticated with an API key.

## Two key types: publishable and secret

Keys come in two **scopes**. The scope decides
which endpoints a key may call:

| Type | Prefix | Where it lives | Can call |
|---|---|---|---|
| **Publishable** | `pk_…` | Client-side, safe to ship in the SDK / your frontend | Start a verification (`/verify`), uploads (`/upload`), SDK config (`/config`), and **minimal** submission status (`/status`: state + reason, **no PII**) |
| **Secret** | `sk_…` | **Backend only**, never in client code | Full verification results and every Risk Intelligence endpoint under `/api/v1` |

Each scope also carries the environment dimension in its prefix:

| Prefix | Type | Environment |
|---|---|---|
| `pk_test_` | Publishable | Sandbox |
| `pk_live_` | Publishable | Production |
| `sk_test_` | Secret | Sandbox |
| `sk_live_` | Secret | Production |

A key looks like `pk_test_aB3dE5fG7hJ9kL1mN3pQ5rS7tU9vW1xY`: the prefix plus 32 random alphanumeric characters.

> **Never ship a secret (`sk_`) key in your SDK, mobile app, or any client code.**
> The publishable key in your frontend can only *start* verifications and poll
> minimal status; it can never read identity data. Fetch results from your
> backend with a secret key. A publishable key hitting a secret-only endpoint
> gets `403 secret_key_required`.

## Authenticating a request

Pass the full key as a Bearer token in the `Authorization` header:

```bash
curl "https://trust.myaza.app/api/kyc/config" \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

The key identifies your organisation and its environment. There is no separate organisation ID to send.
Risk Intelligence uses `https://sandbox.trust.myaza.app/api/v1` with `sk_test_`
and `https://trust.myaza.app/api/v1` with `sk_live_`. The official Node.js SDK
selects the host from its `environment` option.

## Creating and managing keys

API keys are managed in the dashboard under **Developers → API Keys**.

- Pick the **key type** (Publishable or Secret) when creating a key. The **environment selector** in the dashboard header decides whether it's a `_test_` (sandbox) or `_live_` (production) key.
- **Secret keys are shown only once**, at creation. Store the value immediately in a secrets manager; it cannot be retrieved again, only the prefix is displayed afterward.
- **Publishable keys can be viewed anytime** in the dashboard: they're public by design (they ship in your frontend), so there's no secret to protect.
- Creating or revoking a key requires the `api_keys:create` permission. Members without it see keys read-only.
- **Revoke** a key the moment it may be compromised. Revocation is immediate: the next request with that key returns `401`.

> Creating and revoking keys emit the `api_key.created` and `api_key.revoked` [webhook events](https://trust.myaza.co/documentation/webhooks/markdown) so you can wire them into your own security auditing.

## Errors

| Status | Body | Cause |
|---|---|---|
| `401` | `{ "error": "Missing or invalid Authorization header" }` | No `Authorization: Bearer …` header. |
| `401` | `{ "error": "Invalid API key" }` | Unknown or revoked key. |
| `403` | `{ "error": "secret_key_required" }` | A publishable (`pk_`) key was used on a secret-only endpoint (full result or media). Use a `sk_` key from your backend. |
| `403` | `{ "error": "environment_mismatch" }` | The key's environment doesn't match the resource or host (for example, a test key used for a production resource). Keep one environment throughout a flow and use the documented host for that product. |

See [Errors](https://trust.myaza.co/documentation/errors/markdown) for the full list.

## Where each key is used

- **Publishable (`pk_…`)**: the [client SDKs](https://trust.myaza.co/documentation/sdks/markdown), which take an `apiKey` and call
  the API from the user's device, plus any frontend code that starts verifications.
  Match the environment: `pk_test_` with the SDK's `sandbox` environment, `pk_live_`
  with `production`.
- **Secret (`sk_…`)**: your **backend** reading results: `GET /verifications/:id`
  for the full result + PII and `GET /verifications/:id/media/:kind` for captured
  media, plus every Risk Intelligence request under `/api/v1`. Keep it
  server-side only. See the [Risk Intelligence quickstart](https://trust.myaza.co/documentation/risk-intelligence-quickstart/markdown).

## Best practices

- **Never put a secret key in client code.** If a publishable key leaks it can only start verifications; a leaked secret key exposes identity data, so treat it like a password.
- **Never commit a key to a public repository** or paste it where it could be scraped. Revoke immediately if a key leaks.
- Use `_test_` keys while integrating and in CI; reserve `_live_` keys for production traffic.
- Rotate keys periodically.
- Scope keys per service or environment so you can revoke one without disrupting everything.
