> ## Documentation Index
> Fetch the complete documentation index at: https://ayakaleaf-pro.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# GitLab Sync User Credentials Collection

`gitlabSyncUserCredentials` holds one document per user who linked a GitLab account for GitLab Sync. It stores the user's OAuth tokens, encrypted. It belongs to the `gitlab-sync` web module (`services/web/modules/gitlab-sync`). The schema is in `services/web/modules/gitlab-sync/app/models/gitlabSyncUserCredentials.mjs`, and all access goes through `services/web/modules/gitlab-sync/app/src/TokenManager.mjs`.

#### Fields

| Field | Type | Meaning | Source |
| - | - | - | - |
| `_id` | ObjectId | Set by Mongoose when the upsert inserts. | |
| `userId` | ObjectId | The Overleaf user. Required. The schema says `unique: true`, but no index is built (see Indexes); the upsert by `userId` keeps one document per user. | `gitlabSyncUserCredentials.mjs:8`, `TokenManager.mjs:88-95` |
| `gitlab` | String | The JSON `{ accessToken, refreshToken, expiresAt }`, encrypted with `@overleaf/access-token-encryptor`. `expiresAt` is in milliseconds since the epoch, or `null`; `refreshToken` may be `null`. The password comes from `GITLAB_TOKEN_CIPHER_PASSWORD`; the cipher label is `GITLAB_TOKEN_CIPHER_LABEL`, default `2026.10-v3`. Required. | `gitlabSyncUserCredentials.mjs:9-10`, `TokenManager.mjs:18-31`, `services/web/modules/gitlab-sync/app/src/GitLabApiClient.mjs:209-220` |
| `__v` | Number | The Mongoose version key. The schema does not turn it off. | Mongoose default |

#### Who Writes It

| Code | What it does |
| - | - |
| `TokenManager.mjs:88-95` (`saveUserToken`) | Upserts the encrypted credentials for the user. |
| `TokenManager.mjs:99-108` (`linkUserToken`) | Saves new credentials from the OAuth callback (`services/web/modules/gitlab-sync/app/src/GitLabSyncController.mjs:146`). When the user links again, the replaced access token is revoked at GitLab in the background. |
| `TokenManager.mjs:53-78` (`refreshUserToken`) | When the access token is less than 5 minutes from `expiresAt` (`:13,47-49`), it gets new tokens with the refresh token and saves them (`:75`). It runs under the lock `gitlabSyncToken` per user (`:15,54`), because GitLab spends a refresh token on use. |
| `TokenManager.mjs:111-126` (`removeUserToken`) | Revokes the access token at GitLab (best effort), then deletes the document. Called on unlink (`GitLabSyncController.mjs:173`) and when a deleted user expires (`services/web/modules/gitlab-sync/index.mjs:56-58`). |

#### Who Reads It

| Code | What it does |
| - | - |
| `TokenManager.mjs:41-45,81-85` (`getUserCredentials`, `getUserToken`) | Decrypts the credentials for every GitLab API call, refreshing first when the token is about to expire: `services/web/modules/gitlab-sync/app/src/GitLabSyncHandler.mjs` (for example `:27`) and `services/web/modules/gitlab-sync/app/src/GitMerge.mjs:52`. With no document, or credentials that cannot be decrypted or refreshed, it throws `InvalidTokenError`, and the user counts as not linked (`GitLabSyncHandler.mjs:25-37`). |
| `services/web/modules/admin-tools/app/src/AdminUserListManager.mjs:394` | Checks whether the user has a document, for the integrations shown in the admin panel. |

#### Indexes

| Name | Keys | Options | Migration |
| - | - | - | - |
| `_id_` | `_id: 1` | | default |

Mongoose `autoIndex` is off (`services/web/app/src/infrastructure/Mongoose.mjs:7`), so the schema's `unique: true` on `userId` creates nothing. No migration creates indexes for this collection.

#### Notes

* Changing `GITLAB_TOKEN_CIPHER_PASSWORD` makes the stored credentials unreadable. Those users then count as not linked until they link again.
* A deleted user keeps the document until the user expires.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.