phryneas / ssr-only-secrets

This package provides a way to pass secrets from Server Components into the SSR-run of Client Components, without them being accessible in the browser.
https://www.npmjs.com/package/ssr-only-secrets
MIT License
20 stars 1 forks source link
library

ssr-only-secrets

This package provides a way to pass secrets from Server Components into the SSR-run of Client Components without them being accessible in the browser.

This technique was inspired by this comment by @Stevemoretz.

Usage:

Install the package

npm i ssr-only-secrets

Generate a jwk-formatted AES-CBC key, e.g. by running

crypto.subtle
  .generateKey(
    {
      name: "AES-CBC",
      length: 256,
    },
    true,
    ["encrypt", "decrypt"]
  )
  .then((key) => crypto.subtle.exportKey("jwk", key))
  .then(JSON.stringify)
  .then(console.log);

and store the result in an environment variable, e.g. SECRET_KEY_VAR, e.g. by writing it into your .env.local.

SECRET_KEY_VAR={"alg":"A256CBC","ext":true,"k":"...","key_ops":["encrypt","decrypt"],"kty":"oct"}

Now, you can pass "cloaked secrets" from your Server Components into the SSR-run of your Client Components, without them being accessible in your Client Components in the browser.

Example

In a Server Component:

import { cloakSSROnlySecret } from "ssr-only-secrets";

const MyServerComponent = () => {
    const secretValue = "my secret value"
    return <ClientComponent ssrOnlySecret={cloakSSROnlySecret(secretValue, "SECRET_KEY_VAR")} />
}

And in a Client Component

import { useSSROnlySecret } from "ssr-only-secrets";

const ClientComponent = ({ssrOnlySecret}, "SECRET_KEY_VAR") => {
    const value = useSSROnlySecret(ssrOnlySecret);
    console.log(value); // during SSR, this logs "my secret value", but in the browser, it logs "undefined"
}

Alternatively, you can decrypt the secret in your code by calling readSSROnlySecret, e.g. in an Apollo Link:

const value = await readSSROnlySecret(ssrOnlySecret)

Functions

Function Description
cloakSSROnlySecret(secret, encryptionEnvVarName)

Encrypts a secret so that it can be passed from Server Components into the SSR-run of Client Components without them being accessible in the browser.

Use useSSROnlySecret or readSSROnlySecret to decrypt the secret in your Client Component.

Only available in Server Components.

readSSROnlySecret(cloakedSecret, encryptionEnvVarName)

Decrypts a secret that was created in a Server Component using cloakSSROnlySecret.

Calling this in a Browser environment will always return undefined.

Only available in Client Components.

useSSROnlySecret(cloakedSecret, encryptionEnvVarName)

Decrypts a secret that was created in a Server Component using cloakSSROnlySecret. If called during SSR, this hook will briefly suspend your component and then return the decrypted secret.

Calling this in a Browser environment will always return undefined.

Only available in Client Components.