On this page
  1. Install
  2. Compose it once
  3. Node-only and browser declarations
  4. Configuration reference
  5. Operations
  6. Drain legacy encrypted envelopes
  7. Replay-store bridge
  8. Testing
  9. Boundary
  10. API entry points and requirements
  11. Peer dependencies

@playstack/crypto

Workers-compatible encryption, digests, signatures, verification, and secure token generation.

Free. MIT licensed. Check preview availability before installing. See package access.

@playstack/crypto provides Workers-compatible authenticated encryption, digests, signatures, verification, and secure token generation while keeping key ownership explicit.

Install

sh
npm install @playstack/core @playstack/crypto

Compose it once

Resolve secrets at the deployment boundary and inject a clock and Web Crypto implementation. Capability packages receive the resulting suite or the smaller function they require.

ts
import { systemClock } from '@playstack/core'
import { createCrypto } from '@playstack/crypto'

export const applicationCrypto = createCrypto({
  crypto: globalThis.crypto,
  clock: systemClock(),
  encryptionKeys: {
    keys: [
      { id: 'enc-2026-08', key: process.env.ENCRYPTION_KEY_CURRENT!, active: true },
      { id: 'enc-2026-05', key: process.env.ENCRYPTION_KEY_PREVIOUS! },
    ],
  },
  signingKeys: {
    keys: [
      { id: 'sig-2026-08', key: process.env.SIGNING_KEY_CURRENT!, active: true },
      { id: 'sig-2026-05', key: process.env.SIGNING_KEY_PREVIOUS! },
    ],
  },
  maximumTokenTtl: '15m',
  replayStore: singleUseTokenStore,
})

const token = await applicationCrypto.sign({ userId }, { purpose: 'email-verification', ttl: '10m' })

The key strings are canonical padded base64. Encryption keys must decode to exactly 32 bytes; signing keys must decode to at least 32 bytes. Keep old keys available for verification and decryption until their data has expired or been re-encrypted, but mark exactly one key in each keyset active.

Node-only and browser declarations

The public digest, HMAC, and encryption capabilities use minimal DOM-independent interfaces rather than requiring ambient SubtleCrypto. Node-only consumers can use lib: ["es2022"], Node types, and skipLibCheck: false; browser consumers can retain their DOM libraries. Inject the runtime's actual Web Crypto implementation. Enabling browser globals or disabling declaration checking is not required for server projects, and this type boundary does not supply a runtime crypto polyfill.

Configuration reference

CryptoSuiteOptions propertyTypeRequiredPurpose
cryptoWebCryptoYesSupplies subtle and getRandomValues; usually globalThis.crypto.
clockClockYesControls issue, expiry, and verification time.
encryptionKeysKeysetConfigYesAES-GCM keys with one active key.
signingKeysKeysetConfigYesHMAC-SHA-256 keys with one active key.
replayStoreReplayStoreNoAtomically consumes token IDs for single-use verification.
maximumTokenTtlstringNoMaximum signed-token lifetime; defaults to 5m. Supports ms, s, m, or h.

Each KeyConfig has an id, a base64 key, and optional active. IDs are embedded in output envelopes so key rotation does not require trial decryption.

Operations

MethodUse
encrypt / decrypt / decryptTextAuthenticated AES-GCM envelopes for strings or bytes.
needsReencryption / reencryptDetect and migrate values written by an older encryption key.
randomTokenGenerate an opaque base64url token; defaults to 32 bytes and requires at least 16.
digestSha256Produce a stable digest for storing opaque-token lookups.
verifyHmacSha256Compare an expected HMAC without timing-sensitive string comparison.
sign / verifyCreate and verify purpose-bound, expiring structured tokens.

Drain legacy encrypted envelopes

createSecretMigrationCodec() composes the current suite with application-owned legacy decoders. A decoder must positively identify its format; ambiguous and unknown values fail closed, and a malformed current Playstack envelope never falls back to a legacy reader.

Successful legacy decryption returns a current replacement envelope but performs no write. The application persists that replacement with compare-and-swap after the surrounding domain operation succeeds, allowing retired formats and keys to be drained without making them permanent Playstack behavior.

Replay-store bridge

Single-use verification calls one application-owned bridge:

ts
interface ReplayStore {
  consume(jti: string, expiresAtSeconds: number): Promise<boolean>
}

consume must be atomic across all instances. Return true only for the first consumption; retain the marker until expiresAtSeconds. Redis SET NX or a database uniqueness constraint are suitable implementations. If singleUse: true is requested without this bridge, verification fails closed.

Testing

@playstack/crypto/testing exports DeterministicCrypto and MemoryReplayStore. Use them with FakeClock from @playstack/core/testing to test rotation, expiry, and replay behavior without nondeterminism.

Boundary

The package does not load environment variables, manage or derive keys, hash passwords, or provide persistent replay storage. The application owns its secret manager, rotation procedure, and bridge lifecycle.

API entry points and requirements

Reference snapshot: @playstack/crypto@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 pointDeclaration file
@playstack/crypto./dist/index.d.ts
@playstack/crypto/primitives./dist/primitives.d.ts
@playstack/crypto/errors./dist/errors.d.ts
@playstack/crypto/testing./dist/testing.d.ts
@playstack/crypto/playstack.integration.jsonNo TypeScript declaration (asset or metadata export).
@playstack/crypto/package.jsonNo 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

This package declares no peer dependencies. Its ordinary dependencies are resolved by the package manager.

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

Go

Playstack Pro tag
OriginsPricingBlogNewsletterChangelogStatusRoadmap
ContributorsCommunityIn Use ShowcaseCase StudiesPartnersSponsors
FAQsSupportContact

© 2026 Playstack. All rights reserved.

With OSS
Terms of ServicePrivacy PolicyCookie PolicyImprint

By

Commune Software