# Web-server authorization code with PKCE (/docs/auth/flows/web-server-pkce)



Use the web-server authorization-code flow for applications that redirect a user
to Salesforce to authorize access. Kysoql supports PKCE and Salesforce's
confidential-client authentication options for the code exchange.

<SalesforceReference title="OAuth 2.0 Web Server Flow for Web App Integration" href="https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_web_server_flow_ca.htm&language=en_US&type=5" />

## Start authorization [#start-authorization]

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

export async function beginAuthorization() {
  const auth = new SalesforceAuth({
    loginUrl: "https://login.salesforce.com",
    clientId: "external-client-app-id",
  });
  const pkce = await auth.generatePkcePair();
  const url = auth.authorizationUrl({
    redirectUri: "https://app.example.com/oauth/callback",
    scope: ["api", "refresh_token"],
    state: crypto.randomUUID(),
    codeChallenge: pkce.challenge,
  });

  return { url, verifier: pkce.verifier };
}
```

Store the verifier with the browser/session state and validate your own `state`
value when Salesforce redirects back to the application.

## Exchange the code [#exchange-the-code]

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

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

  return auth.exchangeAuthorizationCode({
    code,
    redirectUri: "https://app.example.com/oauth/callback",
    codeVerifier: verifier,
  });
}
```

A confidential client can also provide `clientSecret`, choose
`clientSecretTransport: "basic"`, or supply a `clientAssertion` generated with
[`createOAuthClientAssertion()`](/docs/auth/flows/private-key-jwt).

If Salesforce returns a refresh token, persist rotation with the
[refresh-token flow](/docs/auth/flows/refresh-token) and
[refresh-token storage](/docs/auth/storage).
