Kysoql
Authentication flows

Experience Cloud Code and Credentials

Build Salesforce Headless Identity Authorization Code and Credentials requests for named-user and discovered-user login.

Salesforce Headless Identity's Authorization Code and Credentials flow lets an Experience Cloud customer or partner authenticate inside an off-platform UI while Salesforce performs the identity and authorization work behind the scenes.

Named-user login

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

export async function buildHeadlessLogin(username: string, password: string) {
  const auth = new SalesforceAuth({
    loginUrl: "https://customers.example.my.site.com/customers",
    clientId: "external-client-app-id",
  });
  const pkce = await auth.generatePkcePair();
  const request = auth.codeCredentialsAuthorization({
    redirectUri: "https://app.example.com/oauth/callback",
    username,
    password,
    codeChallenge: pkce.challenge,
  });

  return { request, verifier: pkce.verifier };
}

Send request.url with request.init in the environment that owns the headless login. The builder uses redirect: "manual" so credentials are not automatically forwarded through a redirect.

Named-user credentials default to HTTP Basic for the authorization request. Set credentialsPlacement: "body" when the Salesforce application is configured for POST-body credentials.

Headless user discovery

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

export function buildDiscoveredLogin(identifier: string, password: string) {
  const auth = new SalesforceAuth({
    loginUrl: "https://customers.example.my.site.com/customers",
    clientId: "external-client-app-id",
  });

  return auth.codeCredentialsAuthorization({
    redirectUri: "https://app.example.com/oauth/callback",
    loginHint: identifier,
    password,
    customData: "tenant=customer-portal",
  });
}

User discovery uses POST-body login_hint, password, and optional customdata as required by Salesforce.

Exchange the returned code

When the flow returns an authorization code, exchange it against the same Experience Cloud site base URL. Kysoql preserves configured site paths when it appends Salesforce OAuth endpoints.

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

export function exchangeHeadlessCode(code: string, verifier: string) {
  const auth = new SalesforceAuth({
    loginUrl: "https://customers.example.my.site.com/customers",
    clientId: "external-client-app-id",
  });

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

For guest identity and UVID handling, use Experience Cloud guest authorization.

On this page