Confluence Connector - Authentication
10 min read
Overview
The Confluence Connector authenticates in two directions:
Confluence authentication -- to read pages and attachments from Confluence Cloud or Data Center.
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 ( | Description |
|---|---|---|---|
Cloud | OAuth 2.0 (2LO) |
| Client credentials flow via |
Data Center | OAuth 2.0 (2LO) |
| Client credentials flow via |
Data Center (below 10.1) | Personal Access Token |
| 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.yamlusesunique.authMode, which the Helm template maps toserviceAuthModein the generated tenant config YAML.
Auth Mode | Config Value ( | Description |
|---|---|---|
Cluster-local |
| For connectors running in the same Kubernetes cluster as Unique. Uses service headers ( |
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 |
|---|---|
| Scope management (create child scopes, grant access, set external IDs) |
| Read knowledge base content (file diff, file queries) |
| Write knowledge base content (ingestion, file deletion) |
This user identity is referenced:
In
cluster_localmode: as thex-user-idheader value inserviceExtraHeaders. This must be the ID of an actual service user in Zitadel. It cannot be an arbitrary value.In
externalmode: implicitly via the Zitadel client credentials (zitadelClientId/zitadelClientSecret).
Steps:
Navigate to Zitadel.
Create a new service user.
For
externalmode: assign the required authorizations listed above and generate a client secret. Forcluster_localmode: no authorizations or client secret are needed.Note the user ID (and for
externalmode, the client ID and client secret) for configuration.
For detailed instructions on creating and configuring a service user, see: - How To Configure A Service User - Understand Roles and Permissions
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 for details.
On the first sync cycle, the connector marks the root scope as owned by this tenant's Confluence instance. Every subsequent sync cycle verifies this ownership mark before ingesting content, and the sync fails whenever the recorded owner does not match the Confluence instance configured in connection.baseUrl. The most common misconfiguration that causes this is two tenants being configured with the same ingestion.scopeId while pointing to different Confluence instances: the one whose sync runs first claims ownership, and the others fail on their next sync. See Root Scope Ownership Validation for details.
External mode with Gatekeeper enforced: If the Unique platform has Gatekeeper in enforce mode, the connector's self-grant may be blocked. In that case, an administrator must pre-grant the service user access on the root scope before starting the connector:
mutation {
createScopeAccesses(
scopeId: "<root-scope-id>"
scopeAccesses: [
{ type: MANAGE, entityId: "<service-user-id>", entityType: USER }
{ type: READ, entityId: "<service-user-id>", entityType: USER }
{ type: WRITE, entityId: "<service-user-id>", entityType: USER }
]
)
}Replace <root-scope-id> with the scope ID from ingestion.scopeId and <service-user-id> with the Zitadel service user ID.
3. Set Up Confluence Authentication
Option A: OAuth 2.0 (2LO) -- Cloud
In the Atlassian Admin Console, go to Directory > Service Accounts.
Create a new service account
Add User Role to the Confluence App
Now Create Credentials and select OAuth 2.0
Grant the service account access to the Confluence application and assign the following scopes:
Scope | Type | Purpose |
|---|---|---|
| Classic | CQL search for labeled pages and descendants; covers page body and label expansions |
| Granular | List page attachments (required when attachment ingestion is enabled) |
| Classic | Download attachment binary content (required when attachment ingestion is enabled) |
Note the Client ID and Client Secret.
Obtain the Cloud ID for your Confluence instance (see How do I find my Atlassian Cloud ID?).
Required tenant YAML fields:
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_SECRETThe clientSecret field uses the os.environ/ prefix to resolve the value from an environment variable at runtime (see Secret Resolution).
Option B: OAuth 2.0 (2LO) -- Data Center
In your Confluence Data Center admin console, go to Settings > User Management > Service Accounts.
Create a new service account and generate credentials.
Grant the service account access to the Confluence application and assign the
READ(View content) scope. Space selection is optional. When no spaces are specified, the service account has read access to all spaces.Note the Client ID and Client Secret.
Required tenant YAML fields:
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_SECRETOption C: Personal Access Token -- Data Center Below 10.1 Only (Not Recommended)
Note: PATs are not recommended. Use OAuth 2.0 (2LO) on Data Center 10.1+ instead. PATs are static tokens that do not expire automatically and must be manually rotated. Only use this option on Data Center versions below 10.1 where OAuth 2.0 (2LO) is not available.
In Confluence Data Center, go to Profile > Personal Access Tokens.
Create a new token (the token inherits the creating user's permissions).
Note the generated token value.
Required tenant YAML fields:
confluence:
instanceType: data-center
baseUrl: https://confluence.your-company.com
auth:
mode: pat
token: os.environ/CONFLUENCE_PATThe token field uses the os.environ/ prefix to resolve the value from an environment variable at runtime (see Secret Resolution).
4. Set Up Unique Platform Authentication
Option A: Cluster-Local
Use this mode when the connector is deployed in the same Kubernetes cluster as the Unique platform.
Required tenant YAML fields:
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>:8094Header | Description |
|---|---|
| The company ID in the Unique platform |
| The user ID of the service user in Zitadel. Must be an actual service user -- not an arbitrary value. |
Both headers are validated at config load time. The schema requires that serviceExtraHeaders contains both x-company-id and x-user-id.
Option B: External (Zitadel)
Use this mode when the connector is deployed outside the Unique platform's Kubernetes cluster.
Required tenant YAML fields:
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.comField | Description |
|---|---|
| Zitadel OAuth token endpoint URL |
| Zitadel project ID (resolved via |
| Zitadel client ID for the connector's service user |
| Zitadel client secret (resolved via |
Secret Resolution
Secret fields in the tenant YAML support the os.environ/ENV_VAR_NAME format to resolve values from environment variables at runtime:
os.environ/ENV_VAR_NAMEIf the referenced environment variable is not set or is empty, startup fails with a validation error. Secret values are automatically redacted in logs.
Fields that support os.environ/ resolution:
Field | Example Environment Variable |
|---|---|
|
|
|
|
|
|
|
|
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:
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_SECRETSecret Rotation
The connector uses three types of secrets. All must be stored in Kubernetes Secrets (not ConfigMaps).
Secret | Used By | Purpose |
|---|---|---|
OAuth 2.0 client secret | Confluence Cloud and Data Center | Authenticates the connector to the Confluence OAuth token endpoint |
Personal Access Token | Confluence Data Center < 10.1 only | Static bearer token for API requests (not recommended) |
Zitadel client secret | Unique platform ( | Authenticates the connector to the Unique platform via Zitadel OAuth |
OAuth 2.0 Client Secret (Confluence)
The client secret from the Atlassian service account. The connector uses it to obtain access tokens via the client credentials grant.
What happens if it expires or is revoked: All Confluence API requests fail once the token expires. No new tokens can be acquired. The sync cycle stops producing results until the secret is replaced.
How to rotate:
Generate a new client secret in the Atlassian Admin Console for the service account
Update the Kubernetes Secret with the new value
Restart the connector pods to pick up the new secret
Verify the connector logs show successful token acquisition
Personal Access Token (Data Center < 10.1 only)
A static bearer token associated with a Confluence Data Center user account.
What happens if it expires or is revoked: All Confluence API requests immediately return 401 Unauthorized. The sync cycle stops.
How to rotate:
Generate a new PAT in Confluence Data Center (Profile > Personal Access Tokens)
Update the Kubernetes Secret with the new value
Restart the connector pods
Verify the connector logs show successful API requests
Note: PATs do not expire automatically unless an expiration date was set at creation time. However, they can be revoked at any time by the user or an administrator.
Zitadel Client Secret (External Mode)
The client secret for the connector's Zitadel service account. Used only when serviceAuthMode: external.
What happens if it expires or is revoked: All requests to the Unique Ingestion and Scope Management services fail. Content is read from Confluence but cannot be ingested into the Unique knowledge base.
How to rotate:
Generate a new client secret in Zitadel for the connector's service user
Update the Kubernetes Secret with the new value
Restart the connector pods
Verify the connector logs show successful Zitadel token acquisition
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
Helm Chart Field Mapping
The Helm chart values.yaml uses unique.authMode, which the Helm template maps to serviceAuthMode in the generated tenant config. The following table shows how Helm values map to the actual tenant config fields:
Helm | Tenant Config YAML Field |
|---|---|
|
|
|
|
|
|
|
|
(hardcoded in template) |
|
|
|
Token Flows
Confluence Cloud OAuth 2.0 (2LO)

Token endpoint:https://api.atlassian.com/oauth/token
Request format: JSON body with grant_type, client_id, client_secret.
Confluence Data Center OAuth 2.0 (2LO)

Token endpoint:{baseUrl}/rest/oauth2/latest/token
Request format: URL-encoded form body with grant_type, client_id, client_secret, and scope=READ.
Confluence Data Center PAT
No token exchange is required. The PAT is sent directly as a Bearer token in the Authorization header on every API request.
Token Caching
OAuth 2.0 tokens are cached in memory and automatically refreshed before expiry. PAT tokens are not cached (the static token is sent directly on every request).
Hosting Models
See Architecture -- Hosting Models for the full breakdown of Self-Hosted, Single-Tenant, and Multi-Tenant deployment models, including credential responsibility and data isolation details.
Troubleshooting
OAuth Token Acquisition Failure
Symptom:Failed to acquire Confluence {instanceType} token via OAuth 2.0 2LO in logs.
Causes: - Incorrect clientId or clientSecret - OAuth application not configured for client credentials grant - Network connectivity issues to the token endpoint - For Cloud: incorrect or missing cloudId - For Data Center: incorrect baseUrl (the token endpoint is derived as {baseUrl}/rest/oauth2/latest/token)
Resolution: 1. Verify clientId and clientSecret are correct 2. Confirm the OAuth application is configured for the client credentials grant type 3. Check network egress to Atlassian endpoints (Cloud: api.atlassian.com, auth.atlassian.com, api.media.atlassian.com, and *.atlassian.net on port 443; Data Center: your instance host) 4. Verify the environment variable referenced by os.environ/ is set and non-empty
PAT Authentication Failure
Symptom:401 Unauthorized responses from Confluence Data Center.
Causes: - Token expired or revoked - The user who created the token lacks read access - Incorrect environment variable reference
Resolution: 1. Verify the PAT is still valid in Confluence Data Center administration 2. Regenerate the token if expired 3. Confirm the environment variable referenced by os.environ/ is set and non-empty
Root Scope Not Found
Symptom:Root scope with ID {scopeId} not found error at startup.
Cause: The ingestion.scopeId references a scope that does not exist in the Unique platform.
Resolution: 1. Create the root scope in the Unique platform before starting the connector 2. Verify the scope ID in the tenant configuration matches the actual scope ID
Cluster-Local Header Validation Failure
Symptom: Config validation error: serviceExtraHeaders must contain x-company-id and x-user-id headers.
Cause: The serviceExtraHeaders object is missing one or both required headers.
Resolution: 1. Ensure both x-company-id and x-user-id are present in serviceExtraHeaders 2. The x-user-id must be the ID of an actual service user in Zitadel
TLS Certificate Validation Errors
Symptom:UNABLE_TO_VERIFY_LEAF_SIGNATURE, SELF_SIGNED_CERT_IN_CHAIN, or similar TLS errors when connecting to Confluence or Unique APIs.
Cause: The pod's default trust store does not include the CA that signed the endpoint certificates. This typically happens in environments with a corporate proxy that re-signs TLS traffic or a custom PKI.
Resolution: Provide a CA bundle via the NODE_EXTRA_CA_CERTS environment variable:
connector:
env:
NODE_EXTRA_CA_CERTS: /app/certs/ca-bundle.pemMount the PEM file containing the additional CA certificates into the pod and point the variable to its path.
Secret Resolution Failure
Symptom: Config validation fails with an empty string error for a secret field.
Cause: The environment variable referenced by os.environ/VAR_NAME is not set or is empty.
Resolution: 1. Verify the Kubernetes Secret exists and contains the expected key 2. Verify the envVars entry in the Helm chart references the correct secret name and key 3. Check that the os.environ/ prefix in the tenant YAML matches the environment variable name exactly