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

# Authentication

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

OAuth flows, API keys, and bot tokens all go through the same credential handling. Corsair stores them encrypted and manages them across every tenant.

```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,
    plugins: [
        slack({
            authType: "api_key",
            credentials: { botToken: "xoxb-..." },
        }),
        linear({
            authType: "oauth_2",
            credentials: {
                clientId: process.env.LINEAR_CLIENT_ID,
                clientSecret: process.env.LINEAR_CLIENT_SECRET,
            },
        }),
    ],
});
```

## Auth types

Choose the auth type for each integration:

### API key

For integrations that use static API keys or bot tokens.

```ts theme={null}
slack({
    authType: "api_key",
    credentials: { botToken: "xoxb-your-bot-token" },
})
```

### OAuth 2.0

For integrations that require user authorization.

```ts theme={null}
linear({
    authType: "oauth_2",
    credentials: {
        clientId: process.env.LINEAR_CLIENT_ID,
        clientSecret: process.env.LINEAR_CLIENT_SECRET,
    },
})
```

### Managed

Corsair hosts the OAuth app, so you register nothing in the provider console. Enable it per plugin with `authType: "managed"`. Available for managed plugins on [Hub](/hub/overview).

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

## 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 credentials. Encrypted tokens are persisted only in your database in both modes.
</Note>

## Bring Your Own KMS

If you're using a Key Management Service (AWS KMS, Google Cloud KMS, etc.), you can opt out of Corsair's built-in encryption.

```ts corsair.ts theme={null}
export const corsair = createCorsair({
    plugins: [
        slack({
            authType: "api_key",
            credentials: {
                // Pass your decrypted key directly
                botToken: await kms.decrypt(encryptedToken),
            },
        }),
    ],
});
```

## 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.
