# Confluence Connector - Authentication

## Overview

The Confluence Connector authenticates in two directions:

1. **Confluence authentication** – to read pages and attachments from Confluence Cloud or Data Center.

2. **Unique platform authentication** – to ingest content into the Unique knowledge base.

This guide covers both authentication paths, including credential setup, secret management, and token flows.

## Confluence Authentication Methods

| Instance Type | Auth Method | Config Value (`auth.mode`) | Description |
| --- | --- | --- | --- |
| **Cloud** | OAuth 2.0 (2LO) | `oauth_2lo` | Client credentials flow via `https://api.atlassian.com/oauth/token` |
| **Data Center** | OAuth 2.0 (2LO) | `oauth_2lo` | Client credentials flow via `{baseUrl}/rest/oauth2/latest/token` |
| **Data Center** (below 10.1) | Personal Access Token | `pat` | Static token-based authentication (not recommended; use OAuth 2.0 2LO on Data Center 10.1+) |

- Confluence Cloud supports **only** OAuth 2.0 two-legged (2LO).

- Confluence Data Center 10.1+ supports **both** OAuth 2.0 (2LO) and Personal Access Token (PAT). OAuth 2.0 (2LO) is recommended.

- Confluence Data Center below 10.1 must use **Personal Access Token (PAT)**, as OAuth 2.0 (2LO) is not available on those versions.

## Unique Platform Authentication Methods

The connector's tenant YAML field for selecting the Unique auth mode is `serviceAuthMode` (not `authMode`).

> **Note:** The Helm chart `values.yaml` uses `unique.authMode`, which the Helm template maps to `serviceAuthMode` in the generated tenant config YAML.

| Auth Mode | Config Value (`serviceAuthMode`) | Description |
| --- | --- | --- |
| **Cluster-local** | `cluster_local` | For connectors running in the same Kubernetes cluster as Unique. Uses service headers (`x-company-id`, `x-user-id`) instead of OAuth tokens. |
| **External** | `external` | For connectors running outside the cluster. Authenticates via Zitadel OAuth client credentials. |

## Setup Steps

### 1. Create a Unique Service User

The connector requires a service user in the Unique platform (Zitadel). The user must exist in Zitadel so that a valid `x-user-id` can be referenced.

**Zitadel authorizations** (role assignments) are only enforced in `external` mode. In `cluster_local` mode, the Unique platform does not check Zitadel authorizations. The `x-user-id` must reference an actual existing service user, but its assigned roles are irrelevant.

In `external` mode, the service user must have the following authorizations:

| Permission | Purpose |
| --- | --- |
| `chat.admin.all` | Scope management (create child scopes, grant access, set external IDs) |
| `chat.knowledge.read` | Read knowledge base content (file diff, file queries) |
| `chat.knowledge.write` | Write knowledge base content (ingestion, file deletion) |

This user identity is referenced:

- In `cluster_local` mode: as the `x-user-id` header value in `serviceExtraHeaders`. This **must** be the ID of an actual service user in Zitadel. It cannot be an arbitrary value.

- In `external` mode: implicitly via the Zitadel client credentials (`zitadelClientId` / `zitadelClientSecret`).

Steps:

1. Navigate to Zitadel.
2. Create a new service user.
3. For `external` mode: assign the required authorizations listed above and generate a client secret. For `cluster_local` mode: no authorizations or client secret are needed.
4. Note the user ID (and for `external` mode, the client ID and client secret) for configuration.

### 2. Create the Root Scope in Unique

The connector requires a pre-existing root scope in Unique. The root scope ID is configured in the tenant YAML under `ingestion.scopeId`. If the scope does not exist at startup, the connector fails.

At startup, the connector automatically grants itself access on the root scope and will create child scopes for each Confluence space that has content to ingest. See the [Scope Hierarchy](https://docs.unique.ai/it-operators/integrations-connectors/confluence-connector/confluence-connector-technical-manual/confluence-connector-flows) for details.

### 3. Set Up Confluence Authentication

#### Option A: OAuth 2.0 (2LO) -- Cloud

**Required tenant YAML fields:**

```yaml
confluence:
  instanceType: cloud
  baseUrl: https://your-domain.atlassian.net
  cloudId: your-cloud-id
  auth:
    mode: oauth_2lo
    clientId: your-oauth-client-id
    clientSecret: os.environ/CONFLUENCE_CLIENT_SECRET
```

#### Option B: OAuth 2.0 (2LO) -- Data Center

**Required tenant YAML fields:**

```yaml
confluence:
  instanceType: data-center
  baseUrl: https://confluence.your-company.com
  auth:
    mode: oauth_2lo
    clientId: your-confluence-app-client-id
    clientSecret: os.environ/CONFLUENCE_CLIENT_SECRET
```

#### Option C: Personal Access Token -- Data Center Below 10.1 Only (Not Recommended)

**Required tenant YAML fields:**

```yaml
confluence:
  instanceType: data-center
  baseUrl: https://confluence.your-company.com
  auth:
    mode: pat
    token: os.environ/CONFLUENCE_PAT
```

### 4. Set Up Unique Platform Authentication

#### Option A: Cluster-Local

**Required tenant YAML fields:**

```yaml
unique:
  serviceAuthMode: cluster_local
  serviceExtraHeaders:
    x-company-id: your-company-id
    x-user-id: your-user-id
  ingestionServiceBaseUrl: http://node-ingestion.<namespace>:8091
  scopeManagementServiceBaseUrl: http://node-scope-management.<namespace>:8094
```

#### Option B: External (Zitadel)

**Required tenant YAML fields:**

```yaml
unique:
  serviceAuthMode: external
  zitadelOauthTokenUrl: https://auth.your-unique-instance.com/oauth/v2/token
  zitadelProjectId: your-zitadel-project-id
  zitadelClientId: confluence-connector
  zitadelClientSecret: os.environ/ZITADEL_CLIENT_SECRET
  ingestionServiceBaseUrl: https://ingestion.your-unique-instance.com
  scopeManagementServiceBaseUrl: https://scope-management.your-unique-instance.com
```

## Secret Resolution

Secret fields in the tenant YAML support the `os.environ/ENV_VAR_NAME` format to resolve values from environment variables at runtime:

```none
os.environ/ENV_VAR_NAME
```

### Providing Secrets in Kubernetes

Use Kubernetes Secrets to inject environment variables into the connector pod. The Helm chart supports this via the `connector.envVars` field in `values.yaml`:

```yaml
connector:
  envVars:
    - name: CONFLUENCE_CLIENT_SECRET
      valueFrom:
        secretKeyRef:
          name: confluence-connector-secret
          key: CONFLUENCE_CLIENT_SECRET
    - name: ZITADEL_CLIENT_SECRET
      valueFrom:
        secretKeyRef:
          name: confluence-connector-secret
          key: ZITADEL_CLIENT_SECRET
```

## Best Practices

- **Rotate before expiration** – create the new secret before the old one expires to avoid downtime
- **Use Kubernetes Secrets or a secret manager** – never store secrets in ConfigMaps or plain text
- **Monitor for authentication failures** – failed token acquisition is logged and indicates an expired or revoked secret
- **Document rotation procedures** – include secret rotation in your operational runbook

## Troubleshooting

### OAuth Token Acquisition Failure

**Symptom:** `Failed to acquire Confluence {instanceType} token via OAuth 2.0 2LO` in logs.

### PAT Authentication Failure

**Symptom:** `401 Unauthorized` responses from Confluence Data Center.

### Secret Resolution Failure

**Symptom:** Config validation fails with an empty string error for a secret field.
