> ## Documentation Index
> Fetch the complete documentation index at: https://docs.factorize.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Operator configuration

> Email, OAuth applications, webhooks, and Worker secrets.

These steps apply only to your own deployment. Hosted Factorize users connect existing accounts in [Settings](https://app.factorize.sh/settings); they do not register Factorize OAuth applications or set Worker secrets.

Register provider applications for your deployment origin. Linear requires Issues and Issue labels webhooks and fresh workspace authorization after subscription changes; ClickUp registers its task webhook on connection. Configure the GitHub App credentials and webhook settings for your deployment using the template in `packages/api/.dev.vars.example` and the executable callbacks/webhook routes in `packages/api/src/worker.ts`.

## Account authentication

Factorize owns authentication in PostgreSQL. Create a native account at `/auth/signup` with an email address and a password of 12–200 characters. Emails are case-insensitive. Verify the email before signing in at `/auth/login`; email plus password are accepted. Linear is connected after sign-in from **Settings → Integrations**, only for Linear-backed jobs.

Postmark sends one-hour, single-use verification and password-reset links. `/auth/verify/request` resends verification; `/auth/password-reset` handles recovery. Links never appear in application responses or logs. Passwords use salted PBKDF2-SHA-256. **Change password** in the account menu requires the current password. Password reset, password change and sign-out invalidate existing sessions via membership session versions, including delegated API credentials.

Before deploying, configure `POSTMARK_SERVER_TOKEN` as a **production GitHub environment secret**. The deployment copies it to a Worker secret; the verified sender and transactional message stream are non-secret Worker vars in `packages/api/wrangler.jsonc`. For a manual Postmark preflight, set the following environment variables along with `APP_ORIGIN`:

| Setting | Required value |
| - | - |
| `POSTMARK_SERVER_TOKEN` | Postmark **server** API token for the sending server; never an account token or a committed value |
| `POSTMARK_FROM_EMAIL` | Plain email address on a verified Postmark sender signature or verified domain |
| `POSTMARK_MESSAGE_STREAM` | Active **transactional** stream ID, commonly `outbound` |

`APP_ORIGIN` must be the canonical HTTPS origin, without a trailing slash. Run `npm run auth:validate-email --workspace=factorize` manually when needed: it checks the server token/stream with Postmark and sends one preflight email from/to the configured sender, rejecting unverified senders or sending failures. It prints no credentials. Missing configuration fails the manual check. The deploy workflow does not run this check or send a preflight email. Runtime signup and recovery also fail closed if configuration or delivery fails; users can resend verification after a delivery failure. Local mail testing needs an HTTPS origin and a separate Postmark test server/sender; automated tests mock Postmark and never send mail.

### Existing account migration

Apply `0008_native_accounts.sql` and `0009_remove_auth_usernames.sql` before deploying this code. They reject ambiguous legacy emails that differ only in case (reconcile those identities before retrying migration), preserve tenant IDs, memberships, jobs and encrypted Linear connections, and backfill explicit Linear organization-to-workspace mappings. Existing Linear-only users choose **Forgot password or previously signed in with Linear?**, receive a reset email at their existing address, and set a password. Email possession is required; signup cannot replace an existing account's credentials. Existing native users keep their passwords and may sign in by email; unverified accounts must verify first. A reset never promotes a member to owner. An account with multiple existing owner memberships currently opens the oldest workspace; no new workspace-switching UI is introduced.

Linear OAuth requires an authenticated owner, binds state to that user/workspace, stores the connection there, and never creates a Factorize session. A Linear organization already bound to another workspace cannot be claimed. Existing webhook routes resolve the explicit mapping. Do not delete that binding to work around an account-recovery problem.

### Authentication verification

`npm run check` runs unit/contract tests and Postmark preflight tests. CI also runs the real PostgreSQL authentication suite against a disposable service. To run it locally, set `AUTH_TEST_DATABASE_URL` to an isolated PostgreSQL server whose user can create/drop test databases, then run `npm test --workspace=factorize -- --run test/native-auth.postgres.test.ts`. The suite creates and removes its own database and applies every migration, including a legacy connection fixture before the auth migration.

## Configure Linear

Use authorization-code OAuth and enable **Webhooks** on the OAuth application. Configure:

| Setting | Value |
| - | - |
| Callback URL | `https://your-domain.example/auth/linear/callback` |
| Webhook URL | `https://your-domain.example/webhooks/linear` |
| Webhook events | **Issues** and **Issue labels** |
| Webhook secret | Store as `LINEAR_WEBHOOK_SIGNING_SECRET` |

After changing the webhook settings, re-authorize existing workspaces so Linear creates a fresh workspace subscription.

## Configure ClickUp

Create a ClickUp OAuth application with the callback URL `https://your-domain.example/auth/clickup/callback`, then store its client ID and secret in `CLICKUP_CLIENT_ID` and `CLICKUP_CLIENT_SECRET`. Connecting ClickUp from Settings registers the signed task webhook automatically. ClickUp triggers can filter a list by status, tag, assignee, or creator; all configured rules must match.

## Configuration reference

| Variable | Purpose |
| - | - |
| `LINEAR_CLIENT_ID` | Linear OAuth client ID |
| `LINEAR_CLIENT_SECRET` | Linear OAuth client secret |
| `LINEAR_WEBHOOK_SIGNING_SECRET` | Verifies Linear webhook signatures |
| `CLICKUP_CLIENT_ID` | ClickUp OAuth client ID |
| `CLICKUP_CLIENT_SECRET` | ClickUp OAuth client secret; ClickUp also uses a per-installation webhook secret stored encrypted by Factorize |
| `CREDENTIAL_ENCRYPTION_KEY` | Base64-encoded 32-byte key for encrypted credentials |
| `SESSION_SIGNING_SECRET` | Independent secret for signed browser sessions |
| `APP_ORIGIN` | Public Worker origin, configured in `packages/api/wrangler.jsonc` |
| `OAUTH_KV` | KV binding containing OAuth clients, grants, refresh tokens, and revocation state |

Never commit `.dev.vars` or production secret values. The included `.dev.vars.example` is a safe template.


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