Kysoql
Authentication flows

First-party registration

Use Salesforce OAuth 2.0 for First-Party Applications headless registration and OTP verification.

The first-party registration flow lets a private Experience Cloud application collect registration data, initialize Salesforce registration headlessly, verify the user with an OTP, and receive an authorization code.

Initialize registration

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

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

  return auth.firstPartyAuthorizationChallenge({
    bodyFormat: "json",
    parameters: {
      userdata: {
        username: "user@example.com",
        lastName: "Example",
        email: "user@example.com",
      },
      password: "user-chosen-password",
      login_type: "email",
      client_assertion: clientAssertion,
      code_challenge: codeChallenge,
    },
  });
}

Use accessToken when the Experience Cloud registration policy requires an authenticated integration user. Kysoql adds it as an Authorization: Bearer header. Use uvidHintToken when registration carries guest-session context.

Salesforce strongly recommends PKCE for this flow. Keep the matching code_verifier and use it when exchanging the returned authorization code. Salesforce can return an auth_session while it waits for OTP verification.

Submit the OTP

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

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

  return auth.firstPartyAuthorizationChallenge({
    parameters: {
      auth_session: authSession,
      login_otp: otp,
    },
  });
}

After Salesforce returns kind: "authorized", exchange the authorization code through auth.exchangeAuthorizationCode().

On this page