Kysoql

Refresh-token storage

Persist Salesforce refresh-token rotation in memory, localStorage, Redis, or your own store.

A Salesforce refresh token is a long-lived credential. @kysoql/auth provides a small RefreshTokenStore interface so rotated tokens can be saved safely.

Kysoql stores refresh tokens here, not access tokens. Choose storage that matches your application's security model.

Store contract

import type { RefreshTokenStore } from "@kysoql/auth";

export function encryptedStore(): RefreshTokenStore {
  let encrypted: string | undefined;

  return {
    getRefreshToken: async () => encrypted,
    setRefreshToken: async (token) => {
      encrypted = token;
    },
    deleteRefreshToken: async () => {
      encrypted = undefined;
    },
  };
}

A production store should protect tokens appropriately for its platform. If saving a rotated token fails, let the error propagate. Returning a new access token while losing its replacement refresh token can leave the session unable to refresh again.

Memory

Memory storage is useful for tests, short-lived processes, and tools that do not need refresh state after a restart.

import { createMemoryRefreshTokenStore } from "@kysoql/auth";

export function createStore(initialRefreshToken: string) {
  return createMemoryRefreshTokenStore(initialRefreshToken);
}

Browser localStorage

import { createLocalStorageRefreshTokenStore } from "@kysoql/auth";

const store = createLocalStorageRefreshTokenStore({
  key: "salesforce:refresh-token",
});

The browser adapter uses globalThis.localStorage by default. You can pass a Web Storage-compatible storage object for tests or other runtimes.

localStorage is readable by JavaScript running on the page. Only use it when that exposure fits your threat model. For multi-user apps, use a separate key per application session rather than sharing one token key across users.

Redis

import { createRedisRefreshTokenStore, type RedisLike } from "@kysoql/auth";

export function createStore(client: RedisLike, sessionId: string) {
  return createRedisRefreshTokenStore({
    client,
    key: sessionId,
    prefix: "my-app:salesforce:refresh:",
  });
}

The Redis adapter only needs get, set, and del. Kysoql does not add a TTL or distributed lock. Configure expiry, encryption, ACLs, and concurrency control at the application or infrastructure layer when you need them.

Use a stored token with REST

SalesforceAuth.storedRefreshToken() turns a store into a reusable session and an accessTokenProvider that can be passed straight to @kysoql/rest.

import {
  createRedisRefreshTokenStore,
  SalesforceAuth,
  type RedisLike,
} from "@kysoql/auth";
import { createRestExecutor } from "@kysoql/rest";

export async function createExecutor(
  client: RedisLike,
  initialRefreshToken: string,
) {
  const auth = new SalesforceAuth({
    loginUrl: "https://example.my.salesforce.com",
    clientId: "oauth-client-id",
  });

  const sessionAuth = auth.storedRefreshToken({
    initialRefreshToken,
    refreshTokenStore: createRedisRefreshTokenStore({
      client,
      key: "integration-user",
    }),
  });

  const session = await sessionAuth.getSession();

  return createRestExecutor({
    instanceUrl: session.instanceUrl,
    accessToken: sessionAuth.accessTokenProvider,
  });
}

If the store already contains a token, that token takes precedence over initialRefreshToken. Refresh calls are single-flighted within one JavaScript process and rotated tokens are saved before the new session is returned.

On this page