Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 166 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,101 +1,205 @@
<div align="center">
<a href="https://cipherstash.com">
<img alt="CipherStash Logo" loading="lazy" width="128" height="128" decoding="async" data-nimg="1" style="color:transparent" src="https://cipherstash.com/brand/cipherstash-logo-dark.svg">
<a href="https://cipherstash.com?utm_source=github&utm_medium=stack_readme">
<img alt="CipherStash" width="128" height="128" src="https://cipherstash.com/brand/cipherstash-logo-dark.svg">
</a>
<h1>CipherStash Stack for TypeScript</h1>

<a href="https://cipherstash.com"><img alt="Built by CipherStash" src="https://raw.githubusercontent.com/cipherstash/meta/refs/heads/main/csbadge.svg?style=for-the-badge&labelColor=000"></a>
<a href="https://github.com/cipherstash/stack/blob/main/LICENSE.md"><img alt="License" src="https://img.shields.io/npm/l/@cipherstash/stack.svg?style=for-the-badge&labelColor=000000"></a>
<a href="https://cipherstash.com/docs"><img alt="Docs" src="https://img.shields.io/badge/Docs-333333.svg?style=for-the-badge&logo=readthedocs&labelColor=333"></a>
<a href="https://discord.gg/5qwXUFb6PB"><img alt="Join the community on Discord" src="https://img.shields.io/badge/Join%20the%20community-blueviolet.svg?style=for-the-badge&logo=Discord&labelColor=000000&logoWidth=20"></a>
<p><b>Field-level encryption for TypeScript apps — search encrypted data without decrypting it, with
zero-knowledge key management. Every value gets its own key, and your keys never leave your AWS KMS.</b></p>

<a href="https://www.npmjs.com/package/@cipherstash/stack"><img alt="npm version" src="https://img.shields.io/npm/v/@cipherstash/stack.svg?style=for-the-badge&labelColor=000000"></a>
<a href="https://www.npmjs.com/package/@cipherstash/stack"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@cipherstash/stack.svg?style=for-the-badge&labelColor=000000"></a>
<a href="https://github.com/cipherstash/stack/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/cipherstash/stack?style=for-the-badge&labelColor=000000"></a>
<a href="https://cipherstash.com/docs/stack?utm_source=github&utm_medium=stack_readme"><img alt="Docs" src="https://img.shields.io/badge/Docs-333333.svg?style=for-the-badge&logo=readthedocs&labelColor=333"></a>
<a href="https://discord.gg/5qwXUFb6PB"><img alt="Discord" src="https://img.shields.io/badge/Join%20the%20community-blueviolet.svg?style=for-the-badge&logo=Discord&labelColor=000000"></a>
<a href="https://github.com/cipherstash/stack/blob/main/LICENSE.md"><img alt="License" src="https://img.shields.io/npm/l/@cipherstash/stack.svg?style=for-the-badge&labelColor=000000"></a>

<div>⭐ Star this repo if encryption you can actually query is your thing!</div>
</div>

## What is the stack?
<br/>

> **CipherStash never sees your plaintext.** Data is encrypted in your app with a unique key per value via
> [ZeroKMS][zerokms], rooted in your own [AWS KMS][aws-kms] — so a database breach leaks only ciphertext.
> [See the security architecture →][security-architecture]

## Quick start

- [Encryption](https://cipherstash.com/docs/stack/cipherstash/encryption): Field-level encryption for TypeScript apps with searchable encrypted queries, zero-knowledge key management, and first-class ORM support.
You'll need a free CipherStash account to provision keys and a workspace — it takes about a minute.

## Quick look at the stack in action
**1. Create a free account** → **[cipherstash.com/signup][signup]**

**Encryption**
**2. Initialize your project** — the wizard authenticates you, builds an encryption schema, and wires up your database:

```bash
npx stash init
```

**3. Encrypt, search, and decrypt:**

```typescript
import { Encryption, encryptedTable, encryptedColumn } from "@cipherstash/stack";
import { Encryption } from "@cipherstash/stack";
import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema";

// 1. Define your schema
// Define which columns are encrypted — and how you want to query them
const users = encryptedTable("users", {
email: encryptedColumn("email").equality().freeTextSearch(),
});

// 2. Initialize the client
const client = await Encryption({ schemas: [users] });

// 3. Encrypt
const encryptResult = await client.encrypt("secret@example.com", {
column: users.email,
table: users,
// Encrypt → store the ciphertext in your own database
const enc = await client.encrypt("alice@example.com", { table: users, column: users.email });

// Search WITHOUT decrypting — the part nobody else does
const term = await client.encryptQuery("alice@example.com", {
table: users, column: users.email, queryType: "equality",
});
if (encryptResult.failure) {
// Handle errors your way
}

// 4. Decrypt
const decryptResult = await client.decrypt(encryptResult.data);
if (decryptResult.failure) {
// Handle errors your way
}
// decryptResult.data => "secret@example.com"
// → drop term.data straight into your WHERE clause

// Decrypt when you need the plaintext back
const dec = await client.decrypt(enc.data);
```

## Install
Prefer the long version? Follow the **[5-minute quickstart →][quickstart]**

```bash
npm install @cipherstash/stack
# or
yarn add @cipherstash/stack
# or
pnpm add @cipherstash/stack
# or
bun add @cipherstash/stack
## What's in the Stack

Three building blocks for protecting sensitive data in TypeScript apps — use one, or all three together.

### 🔐 Searchable encryption

Encrypt individual fields and still run real queries against them — exact match, full-text search,
range/sorting, and encrypted JSONB — all on ciphertext, in PostgreSQL.

```typescript
const users = encryptedTable("users", {
email: encryptedColumn("email").equality().freeTextSearch().orderAndRange(),
metadata: encryptedColumn("metadata").searchableJson(), // encrypted JSONB queries
});
```

> [!IMPORTANT]
> **You need to opt out of bundling when using `@cipherstash/stack`.**
> It uses Node.js specific features and requires the native Node.js `require`.
> Read more about bundling in the [documentation](https://cipherstash.com/docs/stack/deploy/bundling).
→ [Searchable encryption][searchable-encryption] · [Schema][schema] · [Encrypt & decrypt][encrypt-decrypt] · [Bulk & model operations][model-ops]

### 🔗 ORM & database integrations

Drop encryption into the stack you already use. Type-safe operators let you query encrypted columns
exactly like normal ones.

| Integration | Status | Guide |
|---|---|---|
| PostgreSQL (raw SQL) | ✅ | [Docs][encryption] |
| Supabase | ✅ | [Docs][supabase] |
| Drizzle ORM | ✅ | [Docs][drizzle] |
| Prisma (Prisma Next) | ✅ | [Docs][prisma-next] |
| DynamoDB | ✅ | [Docs][dynamodb] |

```typescript
// Drizzle: query encrypted columns with auto-encrypting operators
const results = await db.select().from(usersTable)
.where(await ops.eq(usersTable.email, "alice@example.com"));
```

## Features
### 👤 Identity-aware encryption

- **[Searchable encryption](https://cipherstash.com/docs/stack/cipherstash/encryption/searchable-encryption)**: query encrypted data with equality, free text search, range, and [JSONB queries](https://cipherstash.com/docs/stack/cipherstash/encryption/searchable-encryption#jsonb-queries-with-searchablejson).
- **[Type-safe schema](https://cipherstash.com/docs/stack/cipherstash/encryption/schema)**: define encrypted tables and columns with `encryptedTable` / `encryptedColumn`
- **[Model & bulk operations](https://cipherstash.com/docs/stack/cipherstash/encryption/encrypt-decrypt#model-operations)**: encrypt and decrypt entire objects or batches with `encryptModel` / `bulkEncryptModels`.
- **[Identity-aware encryption](https://cipherstash.com/docs/stack/cipherstash/encryption/identity)**: bind encryption to user identity with lock contexts for policy-based access control.
Bind a record's encryption key to the end user's identity, so only *that* user can decrypt their data.
`OidcFederationStrategy` federates your identity provider's OIDC JWT into the client — every ZeroKMS
request then authenticates *as that user* — and `.withLockContext({ identityClaim })` binds the data key to
a claim. Works with any OIDC provider: Clerk, Supabase Auth, Auth0, Okta, and more.

## Integrations
```typescript
import { Encryption, OidcFederationStrategy } from "@cipherstash/stack";

// Authenticate every request as the signed-in user via their OIDC JWT
const client = await Encryption({
schemas: [users],
config: { strategy: OidcFederationStrategy.create(workspaceCrn, () => getUserJwt()) },
});

- [Encryption + Drizzle](https://cipherstash.com/docs/stack/cipherstash/encryption/drizzle)
- [Encryption + Supabase](https://cipherstash.com/docs/stack/cipherstash/encryption/supabase)
- [Encryption + DynamoDB](https://cipherstash.com/docs/stack/cipherstash/encryption/dynamodb)
// Bind the data key to a claim — the same claim is required to decrypt
await client
.encrypt("alice@example.com", { table: users, column: users.email })
.withLockContext({ identityClaim: ["sub"] });
```

## Use cases
→ [Identity-aware encryption][identity]

- **Trusted data access**: ensure only your end-users can access their sensitive data using identity-bound encryption
- **Reduce breach impact**: limit the blast radius of exploited vulnerabilities to only the data the affected user can decrypt
> The Stack also ships a `stash` CLI for auth, schema, and database setup. See the [SDK reference][reference].

## Documentation
## How it works

- [Documentation](https://cipherstash.com/docs)
- [Quickstart](https://cipherstash.com/docs/stack/quickstart)
- [SDK and API reference](https://cipherstash.com/docs/stack/reference)
Encryption happens in your application. Ciphertext is stored as an [EQL][eql] JSON payload in your database;
plaintext and root keys never reach CipherStash. Per-value keys are issued in bulk by ZeroKMS (so millions
of unique keys stay fast), and every decryption is logged for compliance.

## Contributing
→ [Security architecture][security-architecture] · [ZeroKMS][zerokms]

Contributions are welcome and highly appreciated. However, before you jump right into it, we would like you to review our [Contribution Guidelines](CONTRIBUTE.md) to make sure you have a smooth experience contributing.
## Why CipherStash

## Security
- **Trusted data access** — only your end-users can access their sensitive data, enforced cryptographically.
- **Shrink the blast radius** — a breached vulnerability exposes only what one user can decrypt, not your whole table.
- **Meet compliance faster** — exceed the encryption requirements of SOC 2 and ISO 27001, with an audit trail of every decryption.

For our full security policy, supported versions, and contributor guidelines, see [SECURITY.md](./SECURITY.md).
## Install

## License
```bash
npm install @cipherstash/stack # or: yarn / pnpm / bun add @cipherstash/stack
```

This project is [MIT licensed](./LICENSE.md).
> [!IMPORTANT]
> **Opt out of bundling `@cipherstash/stack`.** It uses native Node.js features (a Rust FFI module) and the
> native `require`. [Bundling guide →][bundling]

**Requirements:** Node.js ≥ 18.

## Migrating from Protect.js

> [!NOTE]
> **`@cipherstash/protect` (Protect.js) is now legacy and in maintenance mode.** It still receives critical
> security fixes, but all new development has moved to `@cipherstash/stack`. New projects should use the
> Stack; existing Protect.js users can migrate with the mapping below.

| `@cipherstash/protect` | `@cipherstash/stack` |
|---|---|
| `protect(config)` | `Encryption(config)` |
| `csTable` / `csColumn` | `encryptedTable` / `encryptedColumn` |
| `@cipherstash/protect/identify` | `@cipherstash/stack/identity` |

Method signatures and the `Result` (`data` / `failure`) pattern are unchanged. [Full migration guide →][reference]

## Documentation & community

- 📚 [Documentation][docs] · [Quickstart][quickstart] · [SDK reference][reference]
- 🧩 [Example apps][examples]
- 💬 [Discord community][discord]

## Contributing · Security · License

Contributions are welcome — see [CONTRIBUTE.md][contribute]. For our security policy and responsible
disclosure, see [SECURITY.md][security-policy]. [MIT licensed][license].

<!-- Link definitions — keep all URLs here. CipherStash links carry README UTM params. -->
[signup]: https://cipherstash.com/signup?utm_source=github&utm_medium=stack_readme
[docs]: https://cipherstash.com/docs/stack?utm_source=github&utm_medium=stack_readme
[quickstart]: https://cipherstash.com/docs/stack/quickstart?utm_source=github&utm_medium=stack_readme
[reference]: https://cipherstash.com/docs/stack/reference?utm_source=github&utm_medium=stack_readme
[encryption]: https://cipherstash.com/docs/stack/cipherstash/encryption?utm_source=github&utm_medium=stack_readme
[searchable-encryption]: https://cipherstash.com/docs/stack/cipherstash/encryption/searchable-encryption?utm_source=github&utm_medium=stack_readme
[schema]: https://cipherstash.com/docs/stack/cipherstash/encryption/schema?utm_source=github&utm_medium=stack_readme
[encrypt-decrypt]: https://cipherstash.com/docs/stack/cipherstash/encryption/encrypt-decrypt?utm_source=github&utm_medium=stack_readme
[model-ops]: https://cipherstash.com/docs/stack/cipherstash/encryption/encrypt-decrypt?utm_source=github&utm_medium=stack_readme#model-operations
[supabase]: https://cipherstash.com/docs/stack/cipherstash/encryption/supabase?utm_source=github&utm_medium=stack_readme
[drizzle]: https://cipherstash.com/docs/stack/cipherstash/encryption/drizzle?utm_source=github&utm_medium=stack_readme
[prisma-next]: https://cipherstash.com/docs/stack/cipherstash/encryption/prisma-next?utm_source=github&utm_medium=stack_readme
[dynamodb]: https://cipherstash.com/docs/stack/cipherstash/encryption/dynamodb?utm_source=github&utm_medium=stack_readme
[identity]: https://cipherstash.com/docs/stack/cipherstash/encryption/identity?utm_source=github&utm_medium=stack_readme
[security-architecture]: https://cipherstash.com/docs/stack/reference/security-architecture?utm_source=github&utm_medium=stack_readme
[zerokms]: https://cipherstash.com/docs/stack/cipherstash/kms?utm_source=github&utm_medium=stack_readme
[bundling]: https://cipherstash.com/docs/stack/deploy/bundling?utm_source=github&utm_medium=stack_readme
[eql]: https://github.com/cipherstash/encrypt-query-language
[aws-kms]: https://docs.aws.amazon.com/kms/latest/developerguide/overview.html
[discord]: https://discord.gg/5qwXUFb6PB
[examples]: ./examples
[contribute]: ./CONTRIBUTE.md
[security-policy]: ./SECURITY.md
[license]: ./LICENSE.md
Loading
Loading