Skip to content

docs: update identity-aware encryption to the strategy-based API#57

Merged
coderdan merged 1 commit into
mainfrom
fix/identity-api-deprecation
Jul 9, 2026
Merged

docs: update identity-aware encryption to the strategy-based API#57
coderdan merged 1 commit into
mainfrom
fix/identity-api-deprecation

Conversation

@coderdan

@coderdan coderdan commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Ships before the Supabase launch post. The live docs teach an identity API that no longer does what the page says it does.

The problem

Per-operation CTS tokens were removed in protect-ffi 0.25. LockContext.identify(jwt) is marked @deprecated in the shipped types: "the token fetched here is no longer used by encryption operations." It still compiles and logs a runtime warning.

So a reader copying our current examples gets code that looks like it binds encryption to a user identity, runs without error, and does not bind anything. That's a worse failure mode than a compile error.

Two pages were worse still: use-cases/compliance.mdx and use-cases/provable-access.mdx used client.withLockContext({ identityToken: jwt }).encrypt(...), a call shape that has never existed in any release.

The fix

Authenticate the client as the end user with OidcFederationStrategy, then name the claim to bind:

import { Encryption, OidcFederationStrategy } from "@cipherstash/stack"

const client = await Encryption({
  schemas: [users],
  config: {
    authStrategy: OidcFederationStrategy.create(crn, () => getUserJwt()),
  },
})

await client
  .encrypt(value, { column: users.email, table: users })
  .withLockContext({ identityClaim: ["sub"] })

Lock context is layered on the strategy: it requires OidcFederationStrategy, but the strategy doesn't require lock context. Both strategies are re-exported from @cipherstash/stack.

Files (10)

File Change
encryption/supabase.mdx Launch-critical. Rewrote "Lock context and audit" with Supabase as the OIDC provider
encryption/identity.mdx Canonical page, rewritten. Includes the Clerk/Next.js path
encryption/encrypt-decrypt.mdx Identity + audit examples
encryption/bulk-operations.mdx Removed identify(), dropped the .data! non-null assertion
encryption/models.mdx Same
reference/error-handling.mdx Rewrote "Handling identity errors"; dropped LockContext.identify() from the Result list. Was not in my first sweep (it used identify() without withLockContext)
reference/use-cases/provable-access.mdx 5 call sites on the non-existent identityToken form
reference/use-cases/compliance.mdx 2 call sites, same
reference/comparisons/aws-kms.mdx Passed the Result of identify() straight to withLockContext, missing .data
reference/agent-skills.mdx Skill description referenced LockContext + JWT

Two things reviewers should check

1. Supabase's builder still requires a LockContext instance. EncryptedQueryBuilder.withLockContext(lockContext: LockContext) is typed narrower than the core operations, which accept LockContextInput (LockContext | { identityClaim }). So supabase.mdx uses new LockContext({ context: { identityClaim: ["sub"] } }) while every other page passes the plain object. That's an SDK inconsistency, not a docs one. Worth widening the Supabase type to LockContextInput.

2. @cipherstash/nextjs looks vestigial. It still exports protectClerkMiddleware and getCtsToken (v4.1.1, published yesterday), and is still CTS-token based. But encryption no longer consumes a CTS token, so new LockContext({ ctsToken }) is now inert for key derivation. I rewrote the Clerk section to feed the Clerk session token to OidcFederationStrategy directly, and added a note that the middleware isn't required for identity-aware encryption. Someone who owns that package should confirm.

Note the constructor itself is not deprecated, only identify() and getLockContext(). I've been careful to say so.

Verification

  • Verified against the shipped .d.ts of @cipherstash/stack@0.19.0 and @cipherstash/auth@0.42.0, not the npm READMEs. The @cipherstash/stack README's "Identity-Aware Encryption" section still documents the deprecated identify() flow and should be updated.
  • next build passes; 589 pages generate.
  • Note: bun run build fails on main for an unrelated pre-existing reason. prebuild regenerates content/stack/reference/eql/index.mdx from the EQL manifest with an unclosed <tt> tag, which MDX rejects. Branches fix/eql-docs-strip-tt-tag and fix/eql-mdx-escape-lt already target it. I verified with next build against the committed file.

@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
public-docs Ready Ready Preview, Comment Jul 9, 2026 6:01am

Request Review

The live docs teach `new LockContext().identify(jwt)`. Per-operation CTS
tokens were removed in protect-ffi 0.25, so `identify()` is deprecated: it
still compiles and logs a warning, but the token it fetches is no longer
used by encryption operations. Readers copying these examples get code that
appears to bind an identity and does not.

Correct usage authenticates the client as the end user with
OidcFederationStrategy (config.authStrategy), then names the claim to bind:

  const client = await Encryption({
    schemas: [users],
    config: { authStrategy: OidcFederationStrategy.create(crn, () => getJwt()) },
  })
  await client.encrypt(v, opts).withLockContext({ identityClaim: ["sub"] })

Two pages also used `client.withLockContext({ identityToken })`, a call shape
that never existed in any release.

Verified against the shipped type definitions of @cipherstash/stack 0.19.0
and @cipherstash/auth 0.42.0.
@coderdan coderdan force-pushed the fix/identity-api-deprecation branch from 1b3a701 to 3cb2abd Compare July 9, 2026 06:00
@coderdan coderdan merged commit 94868d2 into main Jul 9, 2026
2 checks passed
coderdan added a commit that referenced this pull request Jul 9, 2026
…sed API

The ported snippet used new LockContext().identify(userJwt), deprecated in
protect-ffi 0.25, and passed the resulting Result straight to
withLockContext() instead of unwrapping .data. main fixed this in #57; this
carries the fix across so merging the port doesn't reintroduce it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant