Authentication

Zero uses a JWT-based flow to authenticate connections to zero-cache.

Frontend

During login:

  1. Your API server creates a JWT and sends it to your client.
  2. Your client constructs a Zero instance with this token by passing it to the auth option.
const zero = new Zero({
  ...,
  auth: token, // your JWT
  userID, // this must match the `sub` field from `token`
});

Server

For zero-cache to be able to verify the JWT, one of the following environment variables needs to be set:

  1. ZERO_AUTH_SECRET - If your API server uses a symmetric key (secret) to create JWTs then this is that same key.
  2. ZERO_AUTH_JWK - If your API server uses a private key to create JWTs then this is the corresponding public key, in JWK format.
  3. ZERO_AUTH_JWKS_URL - Many auth providers host the public keys used to verify the JWTs they create at a public URL. If you use a provider that does this, or you publish your own keys publicly, set this to that URL.

Refresh

The auth parameter to Zero can also be a function:

const zero = new Zero({
  ...,
  auth: async () => {
    const token = await fetchNewToken();
    return token;
  },
  userID,
});

In this case, Zero will call this function to get a new JWT if verification fails.

Client-Side Data Storage

Zero stores client-side data in IndexedDB by default, but this is customizable with the kvStore parameter:

const zero = new Zero({
  // Store data in React Native's SQLite database
  // See https://github.com/Braden1996/react-native-replicache
  kvStore: createReplicacheReactNativeOPSQLiteKVStore,
});

const zero = new Zero({
  // Store data in memory, it disappears on refresh
  kvStore: 'mem',
});

Because multiple users can share the same browser, Zero requires that you provide a userID parameter on construction:

const zero = new Zero({
  ...,
  userID: "user-123",
});

Zero stores each user's data in a different IndexedDB instance. This allows users to quickly switch between multiple users and accounts without resyncing.

If your application is unauthenticated, or if you don't need fast user switching, you can just set userID to a constant like anon or guest:

const zero = new Zero({
  ...,
  userID: "anon",
});

Alternately, if you have more than one set of Zero data per-user (i.e., for different apps in the same domain), you can additonally use the storageKey parameter:

const zero = new Zero({
  ...,
  userID: "user-123",
  storageKey: "my-app",
});

If specified, storageKey is concatenated along with userID and other internal Zero information to form a unique IndexedDB database name.

Zero's IndexedDB databases are prefixed with 'rep' or 'replicache' because ... well because we haven't fixed this yet.

Zero's IndexedDB databases are prefixed with 'rep' or 'replicache' because ... well because we haven't fixed this yet.

Logging Out

When a user logs out, you should consider what should happen to the synced data.

If you do nothing, the synced data will be left on the device. The next login will be a little faster because Zero doesn't have to resync that dta from scratch. But also, the data will be left on the device indefinitely which could be undesirable for privacy and security.

If you instead want to clear data on logout, Zero provides the dropAllDatabases function:

import {dropAllDatabases} from '@rocicorp/zero';

// Returns an object with:
// - The names of the successfully dropped databases
// - Any errors encountered while dropping
const {dropped, errors} = await dropAllDatabases();

Permissions

Any data placed into your JWT (claims) can be used by permission rules on the backend.

const isAdminRule = (decodedJWT, {cmp}) => cmp(decodedJWT.role, '=', 'admin');

See the permissions section for more details.

Examples

See zbugs or hello-zero.