> For the complete documentation index, see [llms.txt](https://docs.envector.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.envector.io/1.5.x/operations-and-management/authentication.md).

# Authentication

Operating enVector authentication: issuing and rotating operational tokens, and managing the Keycloak IdP. For first-time integration and the claim model see [Keycloak / OIDC](/1.5.x/operations-and-management/authentication/keycloak.md); for the SDK-side token flow see [Connection](/1.5.x/sdk-user-guide/initialize/connecting-to-the-service.md).

> This chapter assumes production seeding (strong `KEYCLOAK_LOCAL_USER_PASSWORD`, etc.) is already complete. For initial seeding, see [Keycloak / OIDC → Seeding](/1.5.x/operations-and-management/authentication/keycloak.md#seeding-realm-roles-and-users).

## Session variables

```bash
export COMPOSE_DIR="$(pwd)/docker-compose"
export AUTH_DIR="$(pwd)/scripts/auth"
export KEYCLOAK_HOST_PORT="${KEYCLOAK_HOST_PORT:-8082}"
export KEYCLOAK_REALM="${KEYCLOAK_REALM:-envector}"
```

## 1. Operational token issuance

Issue per-role tokens using the shared user password stored in `.env`:

```bash
set -a; source "${COMPOSE_DIR}/.env"; set +a
PW="${KEYCLOAK_LOCAL_USER_PASSWORD}"

export APP_TOKEN="$("${AUTH_DIR}/get_keycloak_token.sh"      --port "${KEYCLOAK_HOST_PORT}" --realm "${KEYCLOAK_REALM}" app      "${PW}")"
export OPS_TOKEN="$("${AUTH_DIR}/get_keycloak_token.sh"      --port "${KEYCLOAK_HOST_PORT}" --realm "${KEYCLOAK_REALM}" ops      "${PW}")"
export SECURITY_TOKEN="$("${AUTH_DIR}/get_keycloak_token.sh" --port "${KEYCLOAK_HOST_PORT}" --realm "${KEYCLOAK_REALM}" security "${PW}")"
```

| Token            | Primary use                                                       |
| ---------------- | ----------------------------------------------------------------- |
| `APP_TOKEN`      | SDK/application work, Endpoint gRPC calls                         |
| `OPS_TOKEN`      | Operational queries such as `/admin/indexes`, `/admin/keys`       |
| `SECURITY_TOKEN` | Security operations such as `/admin/services`, Audit query/export |

> In production, inject passwords from a secret-management tool (Vault, sealed-secrets, etc.) rather than from `.env`.

## 2. Long-lived refresh token

For work that needs long-term automatic renewal (e.g. the Python SDK `refresh_token` argument), issue a refresh token with the `offline_access` scope:

```bash
"${AUTH_DIR}/get_keycloak_token.sh" \
  --port "${KEYCLOAK_HOST_PORT}" --realm "${KEYCLOAK_REALM}" \
  --field refresh_token \
  --scopes "openid profile email offline_access" \
  app "${PW}" \
  > "app.refresh_token"
chmod 600 app.refresh_token

"${AUTH_DIR}/refresh_keycloak_token.sh" \
  --port "${KEYCLOAK_HOST_PORT}" --realm "${KEYCLOAK_REALM}" \
  --field access_token \
  "$(cat app.refresh_token)" \
  > "app.access_token.refreshed"
```

With `offline_access`, the refresh token can be reused for a long time (around 60 days by default) regardless of the SSO idle timeout. Store token files on a secure medium and restrict access (`chmod 600`).

## 3. Token rotation

| Item                              | Recommended interval  | Notes                                                   |
| --------------------------------- | --------------------- | ------------------------------------------------------- |
| Operational access token          | 1 day to a few hours  | Reissue right before each operational task              |
| Refresh token                     | 30–60 days            | Renew proactively before expiry and store securely      |
| Keycloak admin (kcadmin) password | Quarterly             | Rotate the bootstrap admin password                     |
| Operational user password         | Quarterly             | Re-run the seed or rotate in bulk via the admin console |
| License token (`token.jwt`)       | 30 days before expiry | New token → replace → restart the service               |

## 4. Keycloak operations

### 4.1. Admin console access

```
http://<server-host>:${KEYCLOAK_HOST_PORT:-8082}/admin/
```

* Login: `KEYCLOAK_BOOTSTRAP_ADMIN_USERNAME` / `KEYCLOAK_BOOTSTRAP_ADMIN_PASSWORD` (or the post-seed `envector-admin` + `KEYCLOAK_LOCAL_USER_PASSWORD`).
* In the realm selector, switch to `envector` (`KEYCLOAK_REALM`) to manage users and roles.

> For day-to-day work, use `envector-admin` (realm-admin role) rather than the bootstrap `kcadmin`. Reserve `kcadmin` for emergency recovery.

### 4.2. Admin password rotation

The bootstrap admin (`kcadmin`) lives in the `master` realm.

**Option A — Admin console (recommended):** switch to the `master` realm → **Users → kcadmin → Credentials** → **Set password** with `Temporary` OFF.

**Option B — `kcadm.sh` (inside the container):**

```bash
docker exec -i envector-keycloak-1 /opt/keycloak/bin/kcadm.sh \
  config credentials --server http://127.0.0.1:8080 --realm master \
  --user "${KEYCLOAK_BOOTSTRAP_ADMIN_USERNAME}" --password "<current-password>"

docker exec -i envector-keycloak-1 /opt/keycloak/bin/kcadm.sh \
  set-password -r master --username "${KEYCLOAK_BOOTSTRAP_ADMIN_USERNAME}" \
  --new-password "<new-password>"
```

After rotation, update `KEYCLOAK_BOOTSTRAP_ADMIN_PASSWORD` in `.env` to the same value for consistency on the next seed/restart.

### 4.3. Operational user password rotation

Bulk-rotate seeded user passwords (`app`, `ops`, `security`, …) by changing `KEYCLOAK_LOCAL_USER_PASSWORD` and re-running the seed (idempotent):

```bash
set -a; source "${COMPOSE_DIR}/.env"; set +a

"${AUTH_DIR}/seed_local_keycloak_users.sh" \
  --port "${KEYCLOAK_HOST_PORT}" --realm "${KEYCLOAK_REALM}" \
  --admin-user "${KEYCLOAK_BOOTSTRAP_ADMIN_USERNAME}" \
  --admin-pass "${KEYCLOAK_BOOTSTRAP_ADMIN_PASSWORD}" \
  --user-password "${KEYCLOAK_LOCAL_USER_PASSWORD}" \
  --tenant-id "${KEYCLOAK_LOCAL_TENANT_ID}"
```

To change a single user, use **Users → target → Credentials → Reset password** in the admin console. If passwords are per-user, do not bulk-rotate with `KEYCLOAK_LOCAL_USER_PASSWORD`.

### 4.4. Adding users and roles

See [Keycloak / OIDC → Adding users and roles](/1.5.x/operations-and-management/authentication/keycloak.md#adding-users-and-roles). Required attributes are `principal_id` and `tenant_id`; role candidates are `security`, `ops`, `app`, `keymanager`, `topk`, `pubkey-reader`, `audit-only`, `audit-exporter`.

### 4.5. Data persistence

In production, enable the Keycloak user-data volume so changes survive restarts — see [Keycloak / OIDC → Data persistence](/1.5.x/operations-and-management/authentication/keycloak.md#data-persistence). Without it, re-run the seed after every restart or image update.

### 4.6. External IdP integration

See [Keycloak / OIDC → External IdP integration](/1.5.x/operations-and-management/authentication/keycloak.md#external-idp-integration-reference).

### 4.7. Troubleshooting

| Symptom                                         | Action                                                                                                               |
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `HTTPS required` on token issuance              | Locally the script adds `X-Forwarded-Proto: https`. From an external host, use `--scheme https` or reverse-proxy TLS |
| `invalid_grant` / `Account is not fully set up` | The user's `Required actions` may still contain `Update password`, etc. — remove it in the admin console             |
| Endpoint rejects with `audience mismatch`       | Confirm `ENVECTOR_AUTH_ALLOWED_AUDIENCES` matches the client's `client_id` (default `envector-cli`)                  |
| Roles not reflected after seeding               | Re-run the seed (idempotent); reissue any cached client tokens                                                       |

## 5. Connection security (TLS) model

TLS behavior differs per service; the SDK must be configured accordingly.

| Service                            | Default TLS | Client (SDK) settings                                            |
| ---------------------------------- | ----------- | ---------------------------------------------------------------- |
| **KMS** (gRPC, default 50090)      | TLS         | `kms_secure=True` + `kms_ca_cert` (path to the exported root CA) |
| **Endpoint** (gRPC, default 50050) | No TLS      | `secure=False`                                                   |

* **KMS** is exposed with TLS by default; the client verifies the server certificate with the exported root CA.
* **Endpoint** is exposed without TLS in the default deployment. Passing an `access_token` to `ev.init` flips the default of `secure` to `True`, which makes connections to a non-TLS Endpoint fail — set `secure=False` explicitly. Set `secure=True` only in production where a TLS terminator (reverse proxy, load balancer) sits in front of the Endpoint.

For concrete SDK code, see [Connection](/1.5.x/sdk-user-guide/initialize/connecting-to-the-service.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.envector.io/1.5.x/operations-and-management/authentication.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
