---
title: "@playstack/connections"
description: "Durable, refreshable, encrypted credentials for acting against third-party APIs."
tags: ["package","identity","oauth","connections","free"]
---

{/* package-access:start */}

> **Free.** MIT licensed. Check preview availability before installing. See [package access](/docs/packages#access-policy).

{/* package-access:end */}

`@playstack/connections` manages encrypted, refreshable credentials for acting against third-party APIs on behalf of a user, account member, or account.

## Install

```sh
npm install @playstack/connections @playstack/core @playstack/crypto @playstack/events
```

## Compose providers and storage

```ts
import { createConnections } from '@playstack/connections'
import { githubConnectionProvider } from '@playstack/connections/providers/github'

const github = githubConnectionProvider({
  clientId: process.env.GITHUB_CLIENT_ID!,
  clientSecret: process.env.GITHUB_CLIENT_SECRET!,
})

export const connections = createConnections({
  persistence,
  crypto: applicationCrypto,
  events,
  clock,
  ids,
  providers: [github],
  scope: 'account',
  redirectUri: 'https://app.example/api/connections/callback',
  returnUrlOrigins: ['https://app.example'],
})

const { authorizationUrl } = await connections.begin({
  provider: 'github',
  scope: { type: 'account', id: accountId },
  connectedByUserId: userId,
  returnUrl: 'https://app.example/settings/connections',
  scopes: ['repo:read'],
})
```

OAuth uses PKCE plus a purpose-bound, short-lived, single-use state token. Access and refresh tokens are encrypted before persistence.

## Service configuration

| `ConnectionsOptions` property | Required | Purpose                                                          |
| ----------------------------- | -------- | ---------------------------------------------------------------- |
| `persistence`                 | Yes      | Transactional encrypted connection state and refresh locking.    |
| `crypto`                      | Yes      | Random tokens, digests, encryption, and signed single-use state. |
| `events`, `clock`, `ids`      | Yes      | Typed lifecycle events and deterministic primitives.             |
| `providers`                   | Yes      | Unique provider bridges keyed by provider ID.                    |
| `scope`                       | Yes      | Exactly one of `user`, `accountMember`, or `account`.            |
| `redirectUri`                 | Yes      | Exact OAuth callback URI.                                        |
| `returnUrlOrigins`            | Yes      | Allowlist for post-authorization return URLs.                    |
| `stateTtl`                    | No       | Signed OAuth state lifetime; defaults to `5m`.                   |
| `refreshAheadMs`              | No       | Refresh before expiry window; defaults to five minutes.          |

The configured `scope` must match the selected Prisma artifact variant and persistence adapter option.

## Provider bridge

```ts
interface ConnectionProvider {
  id: string
  capabilities: {
    incrementalScopes: boolean
    refresh: boolean
    revoke: boolean
    rotatingRefreshTokens?: boolean
  }
  authorizationUrl(context: OAuthAuthorizationContext): string
  exchangeCode(code: string, context: OAuthExchangeContext): Promise<TokenSet>
  identify(tokens: TokenSet): Promise<ProviderIdentity>
  refresh?(refreshToken: string): Promise<TokenSet>
  revoke?(tokens: TokenSet): Promise<void>
  validateManual?(credential: string): Promise<ProviderIdentity>
}
```

Capabilities must describe real provider behavior. The service handles connection state, encryption, scope comparison, refresh concurrency, and lifecycle events; provider drivers own protocol-specific URLs and token exchange.

## Provider options

The included driver accepts required `clientId` and `clientSecret`, plus optional GitHub Enterprise `webBaseUrl` and `apiBaseUrl`, REST `apiVersion`, `userAgent`, `allowSignup`, `prompt`, injected `fetch`, and test clock. It supports OAuth App authorization with PKCE and personal access tokens as manual credentials.

`@playstack/connections/providers/oauth2` supplies a standards-based authorization-code, PKCE, refresh, client-authentication, and optional RFC 7009 revocation factory. Named drivers configure GitHub, LinkedIn, Mastodon, and X while preserving the native provider instance and injected Fetch boundary.

AT Protocol is intentionally separate. [`@playstack/atproto`](/docs/packages/identity/atproto) retains official discovery, PAR, DPoP, nonce, refresh, and session-store behavior instead of copying its credentials into a conventional OAuth token record.

## Crypto and persistence bridges

`ConnectionCrypto` is structurally compatible with `@playstack/crypto`. Its `sign` and `verify` methods must preserve purpose and single-use semantics. `ConnectionsPersistence` provides transactional lookup/save and must lock a connection during refresh.

```ts
import { prismaConnectionsPersistence } from '@playstack/connections/prisma'

const persistence = prismaConnectionsPersistence(prisma, { scope: 'account' })
```

Select the matching managed schema variant in `playstack.json`; it is security-critical and non-ejectable. The CLI composes the matching reverse model extension into a managed owner artifact. When an established schema differs physically, use an application-owned persistence adapter and contract tests rather than importing parallel User or Account models.

## Boundary

Connections returns a valid access token; feature code uses the provider’s native SDK directly. The package does not implement login, provider API clients, posting, syndication, or provider-specific UI. Secret sources and provider configuration remain application-owned.

{/* package-reference:start */}

## API entry points and requirements

Reference snapshot: `@playstack/connections@0.1.0-beta.1`. Import only the entry point your runtime needs. Paths below are relative to the installed package; use **Go to Definition** in your editor to inspect exact parameters, return types and overloads. Do not import the declaration-file paths directly.

| Public entry point | Declaration file |
| --- | --- |
| `@playstack/connections` | `./dist/index.d.ts` |
| `@playstack/connections/errors` | `./dist/errors.d.ts` |
| `@playstack/connections/prisma` | `./dist/prisma.d.ts` |
| `@playstack/connections/providers/github` | `./dist/providers/github.d.ts` |
| `@playstack/connections/providers/oauth2` | `./dist/providers/oauth2.d.ts` |
| `@playstack/connections/providers/linkedin` | `./dist/providers/linkedin.d.ts` |
| `@playstack/connections/providers/mastodon` | `./dist/providers/mastodon.d.ts` |
| `@playstack/connections/providers/x` | `./dist/providers/x.d.ts` |
| `@playstack/connections/testing` | `./dist/testing.d.ts` |
| `@playstack/connections/playstack.artifacts.json` | No TypeScript declaration (asset or metadata export). |
| `@playstack/connections/playstack.integration.json` | No TypeScript declaration (asset or metadata export). |
| `@playstack/connections/package.json` | No TypeScript declaration (asset or metadata export). |

Node.js engine requirement: `>=20`. This is not a claim that every entry point works in browsers or Workers.

### Peer dependencies

Keep existing framework versions that satisfy these ranges. Install optional peers only when using the corresponding adapter. The package manager resolves ordinary dependencies separately.

| Peer | Compatible range | When needed |
| --- | --- | --- |
| `@playstack/crypto` | `0.1.0-beta.1` | Required by the package. |

For a complete first program, start with [Getting started](/docs/getting-started). For API lookup and partial-example conventions, see [Reading the reference](/docs/packages#reading-the-reference). Provider failures, lifecycle requirements and application responsibilities remain described in the guide above; types alone do not establish production safety.

{/* package-reference:end */}
