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

# Authentication

> OAuth, API keys, and bot tokens, handled automatically.

Corsair supports several authentication modes across its plugins. You choose an `authType` when registering a plugin — you do not pass tokens or secrets in your application code. Corsair stores credentials encrypted and retrieves the right ones for each tenant at request time.

Check each plugin's [overview page](/plugins/slack/overview) to see which auth types it supports and follow its setup steps.

```ts corsair.ts theme={null}
import { createCorsair } from "corsair";
import { slack } from "@corsair-dev/slack";
import { linear } from "@corsair-dev/linear";

export const corsair = createCorsair({
    multiTenancy: true,
    kek: process.env.CORSAIR_KEK!,
    database: db,
    hub: {
        projectApiKey: process.env.CORSAIR_API_KEY!,
        signingSecret: process.env.CORSAIR_SIGNING_SECRET!,
    },
    plugins: [
        slack({ authType: "managed" }),
        linear({ authType: "oauth_2" }),
    ],
});
```

## Auth types

Not every plugin supports every mode. Open the plugin's docs — for example [Slack](/plugins/slack/overview) or [Linear](/plugins/linear/overview) — and use the **Choose authentication** section as the source of truth.

### Managed OAuth

Corsair hosts the OAuth app, so you register nothing in the provider console. Set `authType: "managed"` and tenants connect through [Hub](/hub/overview).

```ts theme={null}
github({
    authType: "managed",
})
```

### OAuth 2.0

For integrations where you bring your own OAuth app. Set `authType: "oauth_2"` in your plugin config, then enter the **client ID** and **client secret** in the [Hub dashboard](https://hub.corsair.dev/dashboard) — not in `corsair.ts` or environment variables. Tenants authorize their accounts through Hub's connect flow.

```ts theme={null}
linear({
    authType: "oauth_2",
})
```

See [OAuth 2.0](/concepts/oauth) for connect links, solo vs multi-tenant setup, and token lifecycle.

### API key

For integrations that use static API keys or personal access tokens. At the plugin level you only declare the auth type (or omit it when `api_key` is the default). Each tenant supplies their own key during onboarding or on first use — keys are stored encrypted per tenant, not configured once for the whole plugin.

```ts theme={null}
linear({
    authType: "api_key",
})
```

See [API Key](/concepts/api-key) for storing and scoping keys with `withTenant`.

### Bot token

Some plugins accept a bot or app-user token instead of a user API key. Like API keys, bot tokens are **tenant-level**: each tenant provides their own token when connecting. Check the plugin's docs for the exact field name and setup flow.

## Automatic token refresh

When using OAuth, tokens expire. Corsair handles this automatically:

1. Before making a request, checks if the token is expired
2. If expired, uses the refresh token to get a new access token
3. Stores the new token and continues with the request

You never have to think about token rotation.

## Envelope encryption

Corsair uses envelope encryption to protect credentials:

1. You set one **KEK** (Key Encryption Key) in your environment variables
2. Each connection gets its own **DEK** (Data Encryption Key)
3. All credentials are encrypted with the connection's DEK
4. The DEK is encrypted with your KEK

```bash .env theme={null}
CORSAIR_KEK=your-key-encryption-key
```

Each connection has a different DEK, so compromising one connection's key doesn't expose others.

<Note>
  This holds whether you self-host or use [Hub](/hub/overview). Hub is a relay for connect, approval, and webhook surfaces; it stores none of your tenants' tokens. Encrypted tokens are persisted only in your database in both modes.
</Note>

## Multi-tenant credentials

With multi-tenancy, each tenant has their own credentials stored securely.

```ts example.ts theme={null}
// Tenant A's Slack token
const tenantA = corsair.withTenant("tenant_a");
await tenantA.slack.api.messages.post({ ... });

// Tenant B's Slack token — completely separate
const tenantB = corsair.withTenant("tenant_b");
await tenantB.slack.api.messages.post({ ... });
```

Corsair retrieves the correct credentials for each tenant automatically.


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