Skip to main content
The credentials API provides server-side encryption and decryption for platform credentials (session tokens, cookies, API keys) stored in the platform_connections Directus collection. All credentials are encrypted with AES-256-GCM before being written to the database.
These endpoints use X-RBAC-SYNC-SECRET for authentication, not a Directus JWT. They are designed for server-to-server calls only — not for direct use from the browser. The secret is shared between the Directus webhook and this server process.

Encryption

Credentials are encrypted using server/utils/credentialsCrypto.js:
  • Algorithm: AES-256-GCM
  • Key source: CREDENTIALS_ENC_KEY_B64 environment variable (base64-encoded 256-bit key)
  • Functions: encryptJSON(data) → encrypted blob, decryptJSON(blob) → original object
  • Format: The encrypted blob includes the IV and auth tag, stored as a single field (encrypted_credentials) in the platform_connections record
credentials.js is one of two endpoints permitted to use adminFetch for Directus reads (the other is register.js). All other endpoints use the MCP_SERVICE_TOKEN service client. This exception exists because credential access requires admin-level Directus reads that bypass per-user RLS.

Endpoints

MethodPathDescription
POST/api/credentials/storeEncrypt credentials and write to Directus
POST/api/credentials/revealDecrypt credentials from Directus and return them

POST /api/credentials/store

Encrypts a credentials object and saves it to the platform_connections Directus record for the given creator profile.
POST /api/credentials/store
X-RBAC-SYNC-SECRET: <RBAC_SYNC_WEBHOOK_SECRET>
Content-Type: application/json

Body

creatorProfileId
string
required
The UUID of the platform_connections record in Directus. This is the target record that will be updated with the encrypted credentials.
credentials
object
required
The credentials object to encrypt. Shape varies by platform. See platform-specific shapes below.
{
  "creatorProfileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "credentials": {
    "sessionToken": "sess_abc123xyz",
    "authId": "user_9876",
    "cookies": [
      { "name": "sess", "value": "abc", "domain": ".onlyfans.com" }
    ]
  }
}

Response

success
boolean
true when credentials were encrypted and written to Directus.
creatorProfileId
string
The platform_connections record ID (echoed from request).
updated
string
The Directus record ID that was updated.
{
  "success": true,
  "creatorProfileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "updated": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
The endpoint performs a PATCH to /items/platform_connections/{creatorProfileId} and writes three fields:
FieldValue
encrypted_credentialsAES-256-GCM encrypted blob
credentials_version"v1"
credentials_updated_atCurrent UTC timestamp

POST /api/credentials/reveal

Fetches the encrypted credentials from Directus and decrypts them, returning the original credentials object.
POST /api/credentials/reveal
X-RBAC-SYNC-SECRET: <RBAC_SYNC_WEBHOOK_SECRET>
Content-Type: application/json

Body

creatorProfileId
string
required
The UUID of the platform_connections record whose credentials should be decrypted.
{
  "creatorProfileId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Response

success
boolean
true when credentials were found and successfully decrypted.
credentials
object
The decrypted credentials object. Shape matches what was passed to /store.
{
  "success": true,
  "credentials": {
    "sessionToken": "sess_abc123xyz",
    "authId": "user_9876",
    "cookies": [
      { "name": "sess", "value": "abc", "domain": ".onlyfans.com" }
    ]
  }
}

Per-user isolation

Credentials are stored in platform_connections records that are associated with a specific creator_profile_id. Row-level security in PostgreSQL ensures that each user can only access their own records. The reveal endpoint additionally validates that the requesting identity is authorized to access the given creatorProfileId before decrypting.

Platform credential shapes

The credentials object is platform-specific. Common shapes:
{
  "sessionToken": "string",
  "authId": "string",
  "authUid": "string",
  "userAgent": "string",
  "cookies": [{ "name": "string", "value": "string", "domain": "string" }]
}
{
  "authToken": "string",
  "userAgent": "string",
  "cookies": [{ "name": "string", "value": "string", "domain": "string" }]
}
{
  "sessionid": "string",
  "csrftoken": "string",
  "ds_user_id": "string",
  "cookies": [{ "name": "string", "value": "string", "domain": "string" }]
}

Error responses

StatusBodyCause
400{ "success": false, "error": "creatorProfileId required" }Missing required field
400{ "success": false, "error": "credentials object required" }Missing or invalid credentials payload
401{ "success": false, "error": "Unauthorized" }Missing or incorrect X-RBAC-SYNC-SECRET
500{ "success": false, "error": "RBAC_SYNC_WEBHOOK_SECRET not set" }Server misconfiguration — missing env var

Build docs developers (and LLMs) love