# Introduction (/docs/auth)



`@kysoql/auth` handles Salesforce OAuth separately from query building. Pick the flow that fits your application, get a Salesforce session, then pass the access token to [`@kysoql/rest`](/docs/rest) or another Salesforce client.

For most applications, start with `SalesforceAuth`. It keeps the Salesforce login or site URL and client ID in one place, then exposes the supported flows as methods.

For a server-to-server integration that can protect a private key, JWT bearer is the usual starting point. It does not require an interactive login or a stored refresh token.

<SalesforceReference title="OAuth 2.0 JWT Bearer Flow for Server-to-Server Integration" href="https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_jwt_flow_ca.htm&language=en_US&type=5" />

## Install [#install]

<Tabs items="[&#x22;npm&#x22;, &#x22;yarn&#x22;, &#x22;pnpm&#x22;, &#x22;bun&#x22;]" defaultIndex="2">
  <Tab value="npm">
    ```bash
    npm install @kysoql/auth @kysoql/rest
    ```
  </Tab>

  <Tab value="yarn">
    ```bash
    yarn add @kysoql/auth @kysoql/rest
    ```
  </Tab>

  <Tab value="pnpm">
    ```bash
    pnpm add @kysoql/auth @kysoql/rest
    ```
  </Tab>

  <Tab value="bun">
    ```bash
    bun add @kysoql/auth @kysoql/rest
    ```
  </Tab>
</Tabs>

## Server-to-server with JWT bearer [#server-to-server-with-jwt-bearer]

```ts
import { SalesforceAuth } from "@kysoql/auth";
import { createRestExecutor } from "@kysoql/rest";

const auth = new SalesforceAuth({
  loginUrl: "https://login.salesforce.com",
  clientId: "external-client-app-id",
});

export async function createSalesforceExecutor() {
  const authenticate = () =>
    auth.jwtBearer({
      username: "integration@example.com",
      privateKey: { type: "file", path: "./salesforce-auth-key.pem" },
    });

  let session = await authenticate();
  const instanceUrl = session.instanceUrl;

  return createRestExecutor({
    instanceUrl,
    accessToken: async ({ refresh }) => {
      if (refresh) {
        const next = await authenticate();

        if (next.instanceUrl !== instanceUrl) {
          throw new Error("Salesforce instance changed. Recreate the REST client.");
        }

        session = next;
      }

      return session.accessToken;
    },
  });
}
```

Keep the signing key server-side. Private keys use an explicit source object, so Kysoql never has to guess whether a string is a path or PEM content.

Choose the source that matches where your key lives:

* File: `{ type: "file", path }`
* PEM string: `{ type: "pem", value }`
* Web Crypto key: `{ type: "crypto-key", key }`

The [JWT bearer guide](/docs/auth/flows/jwt-bearer) covers Salesforce setup and token renewal in more detail.

## Choose another flow [#choose-another-flow]

Use the [authentication flow guide](/docs/auth/flows) when your application needs interactive login, refresh tokens, client credentials, Experience Cloud identity, SAML, token exchange, or one of Salesforce's first-party application flows.

<SalesforceReference title="OAuth Authorization Flows" href="https://help.salesforce.com/s/articleView?id=remoteaccess_oauth_flows.htm&language=en_US&type=5" />

<Accordions type="single">
  <Accordion title="What happens when a JWT bearer token expires?">
    JWT bearer does not return a refresh token. Give `@kysoql/rest` an access-token provider and let it request a new JWT session after Salesforce returns `401 INVALID_SESSION_ID`.
  </Accordion>

  <Accordion title="What if my flow returns a refresh token?">
    Use [refresh-token storage](/docs/auth/storage). Kysoql can persist rotation in memory, browser `localStorage`, Redis, or a custom store before it exposes the refreshed session.
  </Accordion>

  <Accordion title="Can I use the lower-level functions directly?">
    Yes. Helpers such as `authenticateJwtBearer()`, `exchangeAuthorizationCode()`, and `refreshAccessToken()` remain available when you prefer explicit per-call configuration.
  </Accordion>
</Accordions>

Salesforce's retiring username-password, user-agent, and hybrid user-agent flows are not implemented. Asset tokens are device identity tokens rather than general bearer sessions for SOQL REST calls.
