# Authentication

Source: https://convergingthought.com/docs/getting-started/authentication

> Use project-scoped server keys with explicit permissions and a controlled rotation path.



The public API authenticates each request with a project API key. Console sessions are separate: a browser cookie lets you use the console, but it is not a bearer credential for `/v1`.

```http
Authorization: Bearer YOUR_PROJECT_KEY
```

Keys belong to exactly one project. Optionally restrict a key to one customer in the console. Your server sends `tenant_id` or `X-Internalize-Tenant` for that customer’s memory namespace; a restricted key infers its tenant when omitted. See [Serve multiple customers](/docs/guides/multitenancy). You do not send a project ID in model requests; the key selects the project. If two projects each have a subject named `support`, their knowledge and spending remain separate.

## Create a key [#create-a-key]

Open [API keys](/internalize/app/keys) and choose **Create API key**. Enter a name that identifies the workload, select permissions, and select an expiry. The console offers 30 days, 90 days, one year, or no expiration. Ninety days is selected initially.

The full secret appears only immediately after creation. Copy it to the server environment or your secret manager before closing the dialog. The platform stores a hash for authentication and a short prefix for identification. The listing cannot reveal the full key later.

## Permissions [#permissions]

| Scope         | Allows                                        | Typical use                       |
| ------------- | --------------------------------------------- | --------------------------------- |
| `read`        | Read jobs and subjects in the selected tenant | Monitoring and version inspection |
| `inference`   | Submit inference and read its own jobs        | Serving user questions            |
| `internalize` | Submit learning and read its own jobs         | Knowledge updates                 |
| `adapters`    | Activate a retained adapter                   | Reviewed deployments and rollback |

The default key has only `inference`. Select **Inference + learning** to add `internalize`. **Management only** is hidden under Advanced and requires acknowledgement; it grants `read` and `adapters`, with no inference or learning scope. A submitting key can poll its own jobs without project-wide `read`. Other keys need `read` to inspect those jobs. A key with `internalize` can request automatic activation as part of learning; the `adapters` scope controls the separate manual activation endpoint. Do not grant learning permission to a service you intend to make inference-only.

`GET /v1/models` requires a valid key but no particular scope. It is a useful first authentication check that does not start model work:

```bash
curl --fail-with-body https://convergingthought.com/v1/models \
  -H "Authorization: Bearer $INTERNALIZE_API_KEY"
```

## Keep keys on the server [#keep-keys-on-the-server]

Call Internalize from your backend or worker. Requests carrying an `Origin` header are rejected with `server_keys_only`; browser-side access with a project key is intentionally unsupported. Do not solve this by embedding the key in a proxy URL or disabling browser safeguards.

In a web application, authenticate your own user first, resolve their authorized subject on the server, and make the Internalize request there. Return only the result and metadata the user is entitled to see. Subject IDs alone are not access tokens.

## Rotate or revoke [#rotate-or-revoke]

Create a replacement key with the required scopes, update the intended server, and verify a read request. Then revoke the old key in the console. Revocation prevents later authenticated requests; it does not cancel jobs already admitted or erase their charges.

There can be at most 50 non-revoked keys per project. Expired keys should also be revoked when no longer needed, because the cap counts non-revoked records. If a secret is lost, create a replacement; the original cannot be recovered. If a key may have leaked, revoke it and inspect recent [Activity](/internalize/app/requests) and [Settings activity](/internalize/app/settings).

For `401 unauthorized`, check the exact bearer value, expiry, revocation, and project. For `403 insufficient_scope`, use an appropriately scoped key. Never include the secret itself in a support report.
