This getting started guide steps you through:
- Installing and configuring Protect.js in a standalone project
- Encrypting, searching, and decrypting data in a PostgreSQL database
Important
Prerequisites: Before you start you need to have this software installed:
- Node.js
- TypeScript
- PostgreSQL — see PostgreSQL's documentation for installing
The following is the basic file structure of the standalone project for this getting started guide.
In the src/protect/ directory, we have the table definition in schema.ts and the Protect.js client in index.ts.
📦 <project root>
├ 📂 src
│ ├ 📂 protect
│ │ ├ 📜 index.ts
│ │ └ 📜 schema.ts
│ └ 📜 index.ts
├ 📜 .env
├ 📜 cipherstash.toml
├ 📜 cipherstash.secret.toml
├ 📜 package.json
└ 📜 tsconfig.json
If you're following this getting started guide with an existing app, skip to the next step.
If you're following this getting started guide with a clean slate, create a basic structure by running:
mkdir -p protect-example/src/protect
cd protect-example
git init
npm init -yInstall the @cipherstash/protect package with your package manager of choice:
npm install @cipherstash/protect
# or
yarn add @cipherstash/protect
# or
pnpm add @cipherstash/protectTip
Bun is not currently supported due to a lack of Node-API compatibility. Under the hood, Protect.js uses CipherStash Client which is written in Rust and embedded using Neon.
Lastly, install the CipherStash CLI:
-
On macOS:
brew install cipherstash/tap/stash
-
On Linux, download the binary for your platform, and put it on your
PATH:
Note
You need to opt out of bundling when using Protect.js.
Protect.js uses Node.js specific features and requires the use of the native Node.js require.
You need to opt out of bundling for tools like Webpack, esbuild, or Next.js.
Read more about building and bundling with Protect.js.
Important
Make sure you have installed the CipherStash CLI before following these steps.
To set up all the configuration and credentials required for Protect.js:
stash setupIf you haven't already signed up for a CipherStash account, this will prompt you to do so along the way.
At the end of stash setup, you will have two files in your project:
cipherstash.toml, which contains the configuration for Protect.jscipherstash.secret.toml, which contains the credentials for Protect.js
Warning
Don't commit cipherstash.secret.toml to git; it contains sensitive credentials.
The stash setup command will append to your .gitignore file with the cipherstash.secret.toml file.
Read more about configuration via TOML file or environment variables.
Protect.js uses a schema to define the tables and columns that you want to encrypt and decrypt.
To define your tables and columns, add the following to src/protect/schema.ts:
import { csTable, csColumn } from "@cipherstash/protect";
export const users = csTable("users", {
email: csColumn("email"),
});
export const orders = csTable("orders", {
address: csColumn("address"),
});Searchable encryption:
If you want to search encrypted data in your PostgreSQL database, you must declare the indexes in schema in src/protect/schema.ts:
import { csTable, csColumn } from "@cipherstash/protect";
export const users = csTable("users", {
email: csColumn("email").freeTextSearch().equality().orderAndRange(),
});
export const orders = csTable("orders", {
address: csColumn("address"),
});Read more about defining your schema.
To import the protect function and initialize a client with your defined schema, add the following to src/protect/index.ts:
import { protect } from "@cipherstash/protect";
import { users, orders } from "./schema";
// Pass all your tables to the protect function to initialize the client
export const protectClient = await protect(users, orders);The protect function requires at least one csTable to be provided.
Protect.js provides the encrypt function on protectClient to encrypt data.
encrypt takes a plaintext string, and an object with the table and column as parameters.
Start encrypting data by adding this to src/index.ts:
import { users } from "./protect/schema";
import { protectClient } from "./protect";
const encryptResult = await protectClient.encrypt("secret@squirrel.example", {
column: users.email,
table: users,
});
if (encryptResult.failure) {
// Handle the failure
console.log(
"error when encrypting:",
encryptResult.failure.type,
encryptResult.failure.message
);
}
const ciphertext = encryptResult.data;
console.log("ciphertext:", ciphertext);Run this with:
npx tsx src/index.tsThe encrypt function will return a Result object with either a data key, or a failure key.
The encryptResult will return one of the following:
// Success
{
data: {
c: '\\\\\\\\\\\\\\\\x61202020202020472aaf602219d48c4a...'
}
}
// Failure
{
failure: {
type: 'EncryptionError',
message: 'A message about the error'
}
}Tip
Working with large payloads? Check out the model operations with bulk cryptography functions docs.
Use the decrypt function to decrypt data.
decrypt takes an encrypted data object as a parameter.
import { protectClient } from "./protect";
const decryptResult = await protectClient.decrypt(ciphertext);
if (decryptResult.failure) {
// Handle the failure
}
const plaintext = decryptResult.data;The decrypt function returns a Result object with either a data key, or a failure key.
The decryptResult will return one of the following:
// Success
{
data: 'secret@squirrel.example'
}
// Failure
{
failure: {
type: 'DecryptionError',
message: 'A message about the error'
}
}Tip
Working with large payloads? Check out the model operations with bulk cryptography functions docs.
Encrypted data can be stored in any database that supports JSONB.
To store the encrypted data, specify the column type as jsonb:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email jsonb NOT NULL,
);