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

# Credentials

> Exchange user tokens for integration credentials inside your MCP tool handlers.

Call `kontext.require()` inside your tool handlers to get credentials for any connected integration. The SDK handles token exchange, caching, and error handling.

There are two supported call shapes:

* `kontext.require("github", authInfo.token)` when you have the authenticated user's Kontext access token.
* `kontext.require("github", { userId })` when your confidential server already knows the caller's external subject ID and external auth is configured.

```typescript theme={"system"}
server.tool("list_repos", "List GitHub repos", {}, async (_args, { authInfo }) => {
  const github = await kontext.require("github", authInfo!.token);

  const res = await fetch("https://api.github.com/user/repos", {
    headers: { Authorization: github.authorization },
  });

  const repos = await res.json();
  return { content: [{ type: "text", text: JSON.stringify(repos, null, 2) }] };
});
```

## `IntegrationCredential` shape

`kontext.require()` returns an `IntegrationCredential` object:

```typescript theme={"system"}
interface IntegrationCredential {
  accessToken: string;        // Raw access token
  tokenType: string;          // Usually "Bearer"
  authorization: string;      // Pre-formatted header: "Bearer <token>"
  expiresIn?: number;         // Seconds until expiry
  scope?: string;             // Granted scopes
  integration: string;        // Integration name (e.g. "github")
}
```

The `authorization` field is ready to drop into an HTTP header:

```typescript theme={"system"}
const github = await kontext.require("github", authInfo!.token);

await fetch("https://api.github.com/user", {
  headers: { Authorization: github.authorization },
});
```

## Built-in caching

The SDK caches credentials per integration per token using an LRU cache (max 500 entries). Cache TTL is the minimum of `expiresIn - 60s` and 5 minutes. You do not need to cache credentials yourself.

Repeated calls to `kontext.require("github", token)` within the same session return the cached credential without a network round-trip.

The SDK keeps token-mode and `userId`-mode exchanges in separate cache buckets, so the two flows never collide.

## Exchange by external user ID

Use `{ userId }` for hard-cutover partner or credential-vault flows where your backend already has a stable external identifier for the end user.

```typescript theme={"system"}
const github = await kontext.require("github", {
  userId: "platform-user-123",
});

await fetch("https://api.github.com/user", {
  headers: { Authorization: github.authorization },
});
```

This path is intended for confidential server applications. Kontext treats the `userId` as the RFC 8693 `subject_token` with the custom type `urn:kontext:user-id`.

## Error handling

When a user has not connected an integration, `kontext.require()` throws an `IntegrationConnectionRequiredError`. This error may include a `connectUrl` that the user can open in a browser to authorize the integration.

```typescript theme={"system"}
import {
  Kontext,
  IntegrationConnectionRequiredError,
} from "@kontext-dev/js-sdk/server";

server.tool("list_repos", "List GitHub repos", {}, async (_args, { authInfo }) => {
  try {
    const github = await kontext.require("github", authInfo!.token);
    const res = await fetch("https://api.github.com/user/repos", {
      headers: { Authorization: github.authorization },
    });
    return { content: [{ type: "text", text: JSON.stringify(await res.json()) }] };
  } catch (err) {
    if (err instanceof IntegrationConnectionRequiredError) {
      return {
        content: [{
          type: "text",
          text: JSON.stringify({
            error: "integration_required",
            message: err.message,
            integration: err.integrationName ?? err.integrationId,
            connect_url: err.connectUrl,
          }),
        }],
        isError: true,
      };
    }
    throw err;
  }
});
```

The error has these fields:

| Field             | Type                  | Description                                        |
| ----------------- | --------------------- | -------------------------------------------------- |
| `integrationId`   | `string`              | Integration identifier                             |
| `integrationName` | `string \| undefined` | Human-readable name                                |
| `connectUrl`      | `string \| undefined` | URL for the user to authorize the integration      |
| `code`            | `string`              | Always `"kontext_integration_connection_required"` |

When you call `kontext.require()` with `{ userId }`, `connectUrl` is intentionally omitted. That mode has no bearer token available to mint a user-facing connect session, so your app must route the user through its own connect flow.

MCP clients that support elicitation will display the `connectUrl` to the user automatically when it is present. Return it in the tool response so the AI model can instruct the user.

## `requireCredentials()` for credential-based integrations

Some integrations use API keys or other static credentials instead of OAuth tokens. Use `requireCredentials()` to resolve these.

```typescript theme={"system"}
const creds = await kontext.requireCredentials("my-internal-api", authInfo!.token);

// creds.credentials is a Record<string, string>
await fetch("https://internal.example.com/api", {
  headers: { "X-API-Key": creds.credentials.api_key },
});
```

`requireCredentials()` returns:

```typescript theme={"system"}
interface IntegrationResolvedCredentials {
  integration: string;                  // Original integration name
  integrationId: string;                // Canonical UUID
  credentials: Record<string, string>;  // Key-value credential map
}
```

This method also throws `IntegrationConnectionRequiredError` if the user has not provided the required credentials.

## Known integrations

The SDK provides type hints for common integrations:

* `github`, `slack`, `linear`, `notion`, `jira`, `confluence`
* `gmail`, `google-calendar`, `google-drive`, `figma`
* `stripe`, `shopify`, `salesforce`, `hubspot`, `asana`
* `discord`, `twilio`, `sendgrid`, `openai`, `anthropic`

You can also pass any custom string for integrations you define in the Kontext dashboard.

## Next steps

* [Production](/server/production) -- Deployment checklist for running in production.
* [Server Types](/sdks/typescript/server) -- Full type reference for `IntegrationCredential` and `IntegrationResolvedCredentials`.
* [Errors](/errors) -- Full error hierarchy, error codes, and handling patterns.
