---
schema_version: "1"
id: 3112a70273d815393fd254fda2e415df093600adc0291f6c3a2ef823a7c5e44b
title: "Headless Identity APIs: Headless Passwordless Login Flow for Private Clients"
collection: admin
version: current
locale: en-us
portal_url: https://docs.salesforce.com/admin/current/en-us/xcloud/264-0-0/remoteaccess_headless_passwordless_login_private_clients.md
canonical_url: https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_headless_passwordless_login_private_clients.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: 24c2a32f912be8f31d4239e543c90d7b2a9329a7e266006149a9dcc1af7da72c
description: To simplify the login process for your off-platform app, configure the Headless Passwordless Login Flow. Users log in to your app by entering their email address or phone number and verifying their identity with a one-time password (OTP). On the front end, you control the user experience in your app. On the backend, your app calls Headless Passwordless Login API via an Experience Cloud site to log the user in. These steps show you how the flow works with a private client, like a traditional client-server app, that can keep information confidential.
products:
  - Security
  - Cross Cloud
release: "264"
---
# Headless Identity APIs: Headless Passwordless Login Flow for Private Clients

To simplify the login process for your off-platform app, configure the Headless Passwordless Login Flow. Users log in to your app by entering their email address or phone number and verifying their identity with a one-time password (OTP). On the front end, you control the user experience in your app. On the backend, your app calls Headless Passwordless Login API via an Experience Cloud site to log the user in. These steps show you how the flow works with a private client, like a traditional client-server app, that can keep information confidential.

### Required Editions

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small edition"><colgroup><col></colgroup><tbody><tr class=""><td class="slds-cell-wrap" style="vertical-align:top;">Available in: both Salesforce Classic (not available in all orgs) and Lightning Experience</td></tr><tr class=""><td class="slds-cell-wrap" style="vertical-align:top;">Available in: <strong>Enterprise</strong>, <strong>Unlimited</strong>, and <strong>Developer</strong> Editions</td></tr></tbody></table>

This flow is a variation of the Authorization Code and Credentials Flow, which extends the OAuth 2.0 Authorization Code grant type. Like other variations, it includes calls to Salesforce endpoints to get an authorization code and exchange it for an access token. In this variation, your app exchanges a request identifier and OTP for the authorization code, instead of a username and password as it does in a more traditional headless login flow. The code is then exchanged for an access token.

Before setting up this flow, complete these steps.

- [Complete Prerequisites for Headless Identity](https://help.salesforce.com/s/articleView?id=xcloud.headless_identity_prerequisites.htm&release=264.0.0&type=5 "Before you get started with a Headless Identity implementation for your off-platform apps, cross off these prerequisites in Salesforce.")
- Integrate your off-platform app with Salesforce using one of these options.
    - [Configure an External Client App for the Authorization Code and Credentials Flow](https://help.salesforce.com/s/articleView?id=xcloud.eca_authorization_code_credentials.htm&type=5&language=en_US)
    - [Configure a Connected App for the Authorization Code and Credentials Flow](https://help.salesforce.com/s/articleView?id=xcloud.authorization_code_credentials_configure.htm&release=264.0.0&type=5 "The Authorization Code and Credentials Flow is the foundation of headless login, registration, passwordless login, and guest user identity. Before setting up these features, enable the Authorization Code and Credentials Flow at an org-wide level and configure required settings and access policies for your connected app.")
- [Configure Experience Cloud Settings for Headless Passwordless Login](https://help.salesforce.com/s/articleView?id=xcloud.headless_passwordless_login_settings.htm&release=264.0.0&type=5 "Before you build the Headless Passwordless Login Flow, configure these settings for security and access.")

Here’s an example use case for the Headless Passwordless Login Flow. You work for a travel company that manages customer information in Salesforce, and you already implement headless login and registration in your off-platform app. During your registration process, you collect the user’s email address. To make the login process easier, you configure headless passwordless login with email as the verification method. Now, when users visit your app, they can enter their email address and receive an OTP. After they enter the OTP in your app, and Salesforce verifies their identity, the user is logged in and can access protected Salesforce data, like their travel history.

Optionally, for even more flexibility with your user experience, you can use a headless user discovery Apex handler to retrieve users. Develop your handler to look up users based on their email address, phone number, or any other identifier that can be linked to a Salesforce user. For example, prompt users to log in with their travel confirmation number. When the user enters their confirmation number, Salesforce finds the associated username and sends an OTP to the user's email address. For more information about how to develop your Apex handler, see [Auth.HeadlessUserDiscoveryHandler](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_interface_Auth_HeadlessUserDiscoveryHandler.htm) in the Apex reference guide.

For a private client that can safely store the app’s consumer secret on its own backend, we recommend that you secure your flow by authenticating your calls to Headless Passwordless Login API. Always enable **Require authentication to access this API** in your Experience Cloud settings, and include an access token issued to an internal integration user in your initial request to the `services/auth/headless/init/passwordless/login` endpoint. To get the access token, use a standard OAuth 2.0 flow, like the user-agent flow. For the external client app or connected app that you use for the standard OAuth flow, include the `pwdless_login_api` scope so that it’s reflected in your access token.

Optionally, you can add an extra layer of security by enabling **Require reCAPTCHA to access this API** in your Experience Cloud settings and implementing reCAPTCHA on your app. But authenticated API calls are your best primary line of defense for a private client.

To further secure your flow, we always recommend implementing the OAuth 2.0 Proof Key for Code Exchange (PKCE) extension.

To expand your email template options for the one-time password (OTP) email sent to end users during the flow, opt in to email template allowlisting and create an allowlist with custom templates. See [Use Multiple Email Templates for Headless Flows](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_headless_email_template_allowlist.htm&type=5&language=en_US).

Here’s an overview of the Headless Passwordless Login Flow for a private client.

![Sequence diagram showing headless passwordles login for a private client](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/identity/images/headless_passwordless_login_private_clients.png)

- An end user opens your app and sees a login form natively displayed within your app. They enter their email address or phone number as requested by the login form (1).
- If you're not using a headless user discovery handler, your app finds the username associated with the user’s phone number or email address (2).
- Your app submits a headless POST request to Headless Passwordless Login API (the `services/auth/headless/init/passwordless/login` endpoint on your Experience Cloud site (3).
- (Optional) If you're using a headless user discovery handler, the handler finds the username associated with the data passed in the `login_hint` parameter and verifies that the email address or phone number associated with the user is verified.
- Salesforce returns a success message to your app. It also sends a request identifier, which is used later in the flow (4a).
- Depending on the verification method, Salesforce sends either an email or SMS text message with an OTP to the user (4b).
- Your app natively displays an OTP verification form (5).
- The user receives their OTP and enters it in your app (6).
- If you’re using PKCE, which we strongly recommend, your app generates PKCE parameters (7).
- Your app kicks off the Authorization Code and Credentials Flow with a POST or GET request to the Salesforce authorization endpoint (`services/oauth2/authorize`). The request includes the request ID and OTP, as well as other parameters to identify the app and specify the type of request (8).
- Salesforce verifies the request ID and OTP and returns a 302 redirect to a preconfigured URL that contains the authorization code. If the flow is being executed in the browser, the 302 redirect is processed within the browser, and the response is delivered headlessly to the server-side callback endpoint (9).
- Your server-side callback handler extracts the code and other parameters from the 302 redirect and initiates the code exchange with a POST request to the token endpoint (10).
- Salesforce validates the token request and returns an access token and state (11).
- The server-side callback handler processes the token response and returns the logged-in state to the app. This response can include session details, user info, and possibly the access token (12).
- Your app receives the token response and creates the user’s session (13).
- The user is now logged in and performs an action in your app, like clicking a button to see their order history (14).
- Your app sends an authenticated request to a protected Salesforce API (15).
- The user can now access their Salesforce data in your off-platform app (16).

As mentioned in step 10, for a private client, your build a server-side callback handler that can extract the 302 redirect and return an authorization code to your app. To see how you can build this handler, see [Authorization Code and Credentials Flow for Private Clients](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_authorization_code_credentials_flow.htm&type=5&language=en_US), which includes an example Apex handler exposed as a REST resource.

## End User Enters Their Email Address or Phone Number for Login

The flow starts when an end user visits your app. Your app natively displays a login form requesting only the user’s email address or phone number. Or, if you're using a headless user discovery handler that looks up users based on a different identifier, such as an order number, your app can display a login form prompting the user for the identifier. The end user enters their information and clicks a button to log in.

## Your App Finds the Username

If you're not using a headless user discovery handler, your app looks up the user’s email address or phone number and finds the associated username.

If you're using a headless user discovery handler, your app skips this step. Your handler looks up the user after you submit the initial request.

## Your App Sends a Request to Headless Passwordless Login API

From the browser, your app sends a headless POST request to the headless passwordless login endpoint (services/auth/headless/init/passwordless/login) on your Experience Cloud site.

Include a header to authenticate your request.

Initializing Passwordless Login: Header   
| Parameter | Required? | Description |
| --- | --- | --- |
| `Authorization` | Required if you enable **Require authentication to access this API** in your Experience Cloud settings, which we recommend for private clients. | A Bearer header containing an access token issued to an internal integration user. To get the access token, you can use any standard OAuth flow that Salesforce supports. Ensure that you assign the `pwdless_login_api` scope to your external client app or connected app, or pass it as a parameter during your flow. |

Include these parameters in the request body.

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small " summary="Initializing Passwordless Login: Request Body">
        <caption>Initializing Passwordless Login: Request Body</caption>
        <colgroup>
          <col style="width:33.33333333333333%">
          <col style="width:33.33333333333333%">
          <col style="width:33.33333333333333%">
        </colgroup>
        <thead class="slds-text-title_caps ">
          <tr class="">
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e335">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e338">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e341">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e335 ">
              <code>verificationmethod</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e338 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e341 ">The method that you want to use to verify the user’s identity. You can use
              <code>email</code> or <code>sms</code>.
            </td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e335 ">
              <code>username</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e338 ">Required if you're not using a headless user discovery handler.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e341 ">The username tied to the email address or phone number that the user
              submitted.</td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e335 ">
              <code>recaptcha</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e338 ">
              <p>Required if these conditions apply to you.</p>
              <ul>
                <li>You enabled <strong class="uicontrol">Require reCAPTCHA to access this API</strong> on the
                  Experience Cloud Login &amp; Registration page.</li>

                <li>You're using reCAPTCHA v2 or v3.</li>

              </ul>
            </td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e341 ">An encrypted token issued by the Google reCAPTCHA API when a user completes a
              reCAPTCHA challenge.</td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e335 "><code>recaptchaevent</code></td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e338 ">
              <p>Required if these conditions apply to you:</p>
              <ul>
                <li>You enabled <strong class="uicontrol">Require reCAPTCHA to access this API</strong> on the
                  Experience Cloud Login &amp; Registration settings.</li>

                <li>You're using reCAPTCHA Enterprise.</li>

              </ul>
            </td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e341 ">
              <p>A JSON object containing these subparameters.</p>
              <ul>
                <li><code>token</code>—An encrypted token issued by the Google reCAPTCHA API
                  when a user completes a reCAPTCHA challenge.</li>

                <li><code>siteKey</code>—The Google reCAPTCHA site key. </li>

                <li>(Optional)<code>expectedAction</code>—The action that you expect the user
                  to take to initiate reCAPTCHA, such as <code>login</code>. This parameter
                  maps to Google's <code>action</code> parameter.</li>

                <li><code>projectId</code>—The project ID from Google.</li>

              </ul>
              <p style="margin-bottom:0;">For more information, see <a href="https://cloud.google.com/recaptcha/docs/setup-overview-web" target="_blank">Google's reCAPTCHA documentation</a>.</p>
            </td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e335 ">
              <code>emailtemplate</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e338 ">
              <p>Required to specify multiple email templates if email template allowlisting is
                enabled.</p>
              <p>If you didn’t enable email template allowlisting, you can’t include
                this parameter.</p>
              <p style="margin-bottom:0;">If you don’t include this parameter, Salesforce uses the
                default email template configured in your Experience Cloud settings, regardless of
                whether allowlisting is enabled. If there’s no template configured, Salesforce
                uses a default OTP email template. The email template language for default
                templates is controlled by the user’s language settings in Salesforce.</p>
            </td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e341 ">
              <p>The custom email template developer name. This parameter can include only an
                email template from the allowlist.</p>
              <p style="margin-bottom:0;">To control the language for a custom email
                template, create templates in the desired language </p>
            </td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e335 ">
              <code>login_hint</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e338 ">Required if you're using a headless user discovery Apex handler.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e341 ">An identifier that your Apex handler can use to find a user's Salesforce
              account. For example, collect a user's order number in your app and pass it in the
              <code>login_hint</code> parameter. We send the <code>login_hint</code>
              value straight to your Apex handler.
            </td>

          </tr>
        </tbody>
      </table>

Here’s an example request to Headless Passwordless Login API. In this example, authentication is required but reCAPTCHA isn’t. This request is for an implementation that doesn't use a headless user discovery handler.

```
POST /services/auth/headless/init/passwordless/login? HTTP 1.1
Host: MyExperienceCloudSite.my.site.com
Authorization: Bearer <access token>
{
 "verificationmethod": "email",
"username": "janice.edwards@example.com",
"emailtemplate": "unfiled$public/SalesNewCustomerEmail"
}
```

Here's an example request if you’re using a headless user discovery handler.

```
POST /services/auth/headless/init/passwordless/login? HTTP 1.1
Host: MyExperienceCloudSite.my.site.com
Authorization: Bearer <access token>
{
 "verificationmethod": "email",
"login_hint": "<user identifier such as email address, phone number, order number>",
"emailtemplate": "unfiled$public/SalesNewCustomerEmail"
}
```

## (Optional) Headless User Discovery Handler Finds User

If you're using a headless user discovery handler, the handler takes the `login_hint` parameter and finds the associated user. The handler confirms that the email address or phone number for the user is verified.

For an example handler, see [Auth.HeadlessUserDiscoveryHandler](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_interface_Auth_HeadlessUserDiscoveryHandler.htm) in the Apex Reference Guide.

## Salesforce Returns a Request Identifier to Your App

If the request is successful, Salesforce sends back a success message that includes an `identifier` for the request, which is important later in the flow when it’s exchange for an access token. Here’s an example success message.

```
{
"status": "success",
"email": "jedwards@example.com",
"identifier": "0RXXXXXXXX"
}
```

## Salesforce Sends an OTP to the User

Immediately after Salesforce sends the request identifier to your app, it also sends the user an email or SMS text message with the OTP.

## Your App Displays a Verification Form

In your app, you natively display a verification form where the user can enter their OTP.

## End User Enters OTP

The end user receives the OTP via email or text message and enters it in the verification form in your app.

## Your App Generates Parameters for PKCE

If you’re using the PKCE extension—which we strongly recommend— your app generates `code_verifier` and `code_challenge` parameters.

The PKCE specification defined in [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) also includes an optional `code_challenge_method` parameter that you can send in the authorization request. Salesforce ignores any value that you send in this parameter and defaults to `SHA256`.

## Your App Sends a Request to the Authorization Endpoint

As soon as the user verifies their identity by entering the OTP, your app initializes the Authorization Code and Credentials Flow with a request to the authorization endpoint, where it exchanges the request ID and OTP for an authorization code.

Include these headers in the authorization request.

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small " summary="Authorization Request: Headers">
        <caption>Authorization Request: Headers</caption>
        <colgroup>
          <col style="width:33.33333333333333%">
          <col style="width:33.33333333333333%">
          <col style="width:33.33333333333333%">
        </colgroup>
        <thead class="slds-text-title_caps ">
          <tr class="">
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e651">Header</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e654">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e657">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Header" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e651 ">
              <code>Auth-Request-Type</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e654 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e657 ">Specifies the type of request you want to make to Salesforce. For headless
              passwordless login, this value must be set to <code>passwordless-login</code>.</td>

          </tr>
          <tr class="">
            <td data-label="Header" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e651 ">
              <code>Auth-Verification-Type</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e654 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e657 ">The method used to verify the user’s identity. Salesforce supports two values for the
              verification method: <code>email</code> and <code>sms</code>.</td>

          </tr>
          <tr class="">
            <td data-label="Header" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e651 ">
              <code>Authorization</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e654 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e657 ">
              <p>A Basic header identifying the passwordless login request so that Salesforce can link
                it to the user’s stored information.</p>
              <p style="margin-bottom:0;">Include the request identifier (<code>identifier</code>) provided by Salesforce and the OTP used to verify
                the user’s identity. Append these values to each other in the format <code>&lt;identifier:OTP&gt;</code> and Base64-encode the resulting value.
                The entire header value looks like <code>&lt;Base64-encoded
          identifier:OTP&gt;</code>.</p>
            </td>

          </tr>
          <tr class="">
            <td data-label="Header" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e651 ">
              <code>Uvid-Hint</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e654 ">
              <p>No. If you implement the guest user flow on your app, you can optionally use this
                header to pass in a JSON Web Token (JWT)-based access token containing a unique visitor ID
                (<code>UVID</code>) tied to a guest user’s identity. By passing the
                <code>UVID </code> into a named user flow, you can carry contextual
                information from a guest user session, like the user’s cookie preferences, into a named user
                session.
              </p>
              <p style="margin-bottom:0;">Instead of passing a JWT-based token with a <code>UVID</code> in a header, you can also pass the plain <code>UVID</code> value in the request body.</p>
            </td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e657 ">A JWT-based access token containing a <code>UVID</code> value,
              which is a Version 4 universally unique identifier (UUID) that’s generated and managed
              entirely by your app. To get an access token with a <code>UVID</code>, you must enable your external client app or connected app to issue
              JWT-based access tokens and implement the headless guest flow on your app.</td>

          </tr>
        </tbody>
      </table>

Include these parameters in the request body.

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small " summary="Authorization Request: Body">
        <caption>Authorization Request: Body</caption>
        <colgroup>
          <col style="width:33.33333333333333%">
          <col style="width:33.33333333333333%">
          <col style="width:33.33333333333333%">
        </colgroup>
        <thead class="slds-text-title_caps ">
          <tr class="">
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e788">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e791">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e794">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e788 ">
              <code>response_type</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e791 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e794 ">The OAuth 2.0 grant type that your app requests. For the Authorization Code and
              Credentials Flow, this value must be <code>code_credentials</code>.</td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e788 ">
              <code>client_id</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e791 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e794 ">The external client app or connected app consumer key.</td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e788 ">
              <code>redirect_uri</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e791 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e794 ">
              <p>The URL where users are redirected after successful authentication. The <code>redirect_uri</code> must match one of the values in the external
                client app or connected app Callback URL field. Otherwise, the approval fails. This value
                must be URL encoded.</p>
              <p style="margin-bottom:0;">For private clients, use a <code>redirect_uri</code> that points to your server-side callback handler.</p>
            </td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e788 ">
              <code>code_challenge</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e791 ">Only if you’re using PKCE. PKCE is strongly recommended.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e794 ">
              <p>Specifies the SHA256 hash value of the <code>code_verifier</code> value in the token request. Set this parameter to help prevent
                authorization code interception attacks. The value must be Base-64 URL encoded as defined in
                <a href="https://tools.ietf.org/html/rfc4648#section-5" target="_blank">https://tools.ietf.org/html/rfc4648#section-5</a>
              </p>
              <p>If a <code>code_challenge</code> is
                provided in the authorization request and a <code>code_verifier</code> is provided in the token request, Salesforce compares the two
                values. If the <code>code_challenge</code> is invalid or doesn’t
                match, the login fails with the <code>invalid_request</code> error
                code.</p>
              <p style="margin-bottom:0;">If the <code>code_challenge</code> is provided in the
                authorization request, but there’s no <code>code_verifier</code> in
                the token request, the login fails with the <code>invalid_grant</code> error code.</p>
            </td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e788 ">
              <code>uvid_hint</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e791 ">
              <p>No. If you implement the guest user flow on your app, you can optionally use this
                parameter to pass in a <code>UVID</code> value tied to a guest
                user’s identity, carrying contextual information from a guest user session into a named user
                session.</p>
              <p style="margin-bottom:0;">Instead of passing the <code>UVID</code> in the request
                body, you can also pass it in a JWT-based token with a <code>UVID</code> via the <code>UVID-Hint</code> header.</p>
            </td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e794 ">A plain <code>UVID</code> value, which is a Version 4 UUID
              that’s generated and managed entirely by your app. To get a <code>UVID</code>, you must enable your external client app or connected app to issue
              JWT-based access tokens and implement the headless guest flow on your app.</td>

          </tr>
        </tbody>
      </table>

Here’s an example request to the authorization endpoint. This example includes PKCE.

```
POST /services/oauth2/authorize? HTTP 1.1
Host: MyExperienceCloudSite.my.site.com
Auth-Request-Type: passwordless-login
Auth-Verification-Type: email
Authorization: Basic <base64-encoded identifier:OTP

response_type=code_credentials&
client_id=***********&
redirect_uri=https://www.MyDomainName.my.site.com/services/apexrest/code/exchange&
code_challenge=********
```

## Salesforce Verifies the Request and Returns a 302 Redirect

When the request hits the authorization endpoint, Salesforce verifies the request identifier and OTP. Salesforce then returns an HTTP 302 redirect to a preconfigured URL containing the authorization code. If the flow is happening in the browser, the 302 redirect is processed in the browser and Salesforce automatically sends the redirect response to the redirect URL, which is the server-side callback endpoint. Here’s an example preconfigured URL.

```
https://www.MyDomainName.my.site.com/services/apexrest/code/exchange?code=aPrxC1*******
&sfdc_community_url=https%3A%2F%2FMyDomainName.my.site.com&sfdc_community_id=0DBxxxxxxxxxxxx
```

## Server-Side Callback Handler Extracts Code and Performs Code Exchange

The server-side callback handler extracts the authorization code and other parameters from the 302 redirect. It then initiates the code exchange by sending a headless POST request to the token endpoint.

This request has no headers. Include these parameters in the request body.

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small " summary="Token Exchange Request: Body Parameters">
        <caption>Token Exchange Request: Body Parameters</caption>
        <colgroup>
          <col style="width:33.33333333333333%">
          <col style="width:33.33333333333333%">
          <col style="width:33.33333333333333%">
        </colgroup>
        <thead class="slds-text-title_caps ">
          <tr class="">
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e986">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e989">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d77200e992">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e986 ">
              <code>code</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e989 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e992 ">The authorization server creates an authorization code, which is a short-lived token,
              and passes it to the client after successful authentication. The client sends the
              authorization code to the authorization server to obtain an access token and, optionally, a
              refresh token.</td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e986 ">
              <code>client_id</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e989 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e992 ">The consumer key of the external client app or connected app.</td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e986 ">
              <code>client_secret</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e989 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e992 ">The consumer secret of the external client app or connected app. In this flow, it acts
              as a password that the app uses to access Salesforce.</td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e986 ">
              <code>redirect_uri</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e989 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e992 ">
              <p>The URL where users are redirected after a successful authentication. The redirect URI
                must match one of the values in the external client app or connected app Callback URL field.
                Otherwise, the approval fails. This value must be URL encoded.</p>
              <p style="margin-bottom:0;">For private clients, use a
                <code>redirect_uri</code> that points to your server-side callback
                handler.
              </p>
            </td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e986 ">
              <code>grant_type</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e989 ">Yes.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e992 ">The type of validation that the app can provide to prove it’s a safe visitor. For the
              Authorization Code and Credentials Flow, the value must be <code>authorization_code</code>.</td>

          </tr>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e986 ">
              <code>code_verifier</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e989 ">Only if you’re using PKCE.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d77200e992 ">
              <p>Specifies 128 bytes of random data with high entropy to make guessing the code value
                difficult. Set this parameter to help prevent authorization code interception attacks. The
                value must be base64url-encoded as defined in <a href="https://datatracker.ietf.org/doc/html/rfc4648#section-5" target="_blank">https://datatracker.ietf.org/doc/html/rfc4648#section-5</a>.</p>
              <p>If there’s a <code>code_verifier</code> value in the token request and a <code>code_challenge</code> value in the authorization request, Salesforce compares the two
                values. If the <code>code_verifier</code> is invalid or doesn’t
                match, the login fails with the <code>invalid_grant</code> error
                code.</p>
              <p style="margin-bottom:0;">If the <code>code_verifier</code> value is in the token
                request, but there’s no <code>code_challenge</code> value in the
                authorization request, the login fails with the <code>invalid_grant</code> error code.</p>
            </td>

          </tr>
        </tbody>
      </table>

Here’s an example token request. This example uses PKCE.

```
POST services/oauth2/token? HTTP 1.1
Host: MyExperienceCloudSite.my.site.com

code=********&
client_id=**********&
client_secret=*********&
redirect_uri=https://www.MyDomainName.my.site.com/services/apexrest/code/exchange&
grant_type=authorization_code&
code_verifier=*******
```

## Salesforce Grants an Access Token

After validating the app’s credentials. Salesforce returns an access token to the server-side callback handler. Here’s an example access token response in JSON format.

```
{
"access_token":"*******************",
"sfdc_community_url":"https://MyDomainName.my.site.com",
"sfdc_community_id":"0DBxxxxxxxxxxxx",
"signature":"ts6wm/svX3jXlCGR4uu+SbA04M6qhD1SAgVTEwZ59P4=",
"scope":"openid api",
"id_token":"XXXXXX",
"instance_url":"https://yourInstance.salesforce.com",
"id":"https://yourInstance.salesforce.com/id/00Dxxxxxxxxxxxx/005xxxxxxxxxxxx",
"token_type":"Bearer",
"issued_at":"1667600739962"
}
```

The access token response contains these parameters.

Token Response Parameters   
| Parameter | Required? | Description |
| --- | --- | --- |
| `access_token` | Yes. | OAuth token that an external client app or connected app uses to request access to a protected resource on behalf of the client application. Additional permissions in the form of scopes can accompany the access token. |
| `id` | Yes. | An identity URL that can be used to identify the user and to query for more information about the user. See [Identity URLs](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_using_openid.htm&type=5&language=en_US). |
| `id_token` | No. | A signed data structure that contains authenticated user attributes, including a unique identifier for the user and a timestamp indicating when the token was issued. It also identifies the requesting app. See [OpenID Connect specifications](https://openid.net/specs/openid-connect-basic-1_0-28.html). |
| `instance_url` | Yes. | A URL indicating the instance of the user’s org. For example, `https://yourInstance.salesforce.com/`. |
| `issued_at` | Yes. | A timestamp of when the signature was created, expressed as the number of milliseconds from 1970-01-01T0:0:0Z UTC. |
| `refresh_token` | No. | Token obtained from the web server, user-agent, or hybrid app token flow. This value is a secret. Take appropriate measures to protect it. This parameter is returned only if your external client app or connected app is set up with a `refresh_token` scope. |
| `signature` | Yes. | Base64-encoded HMAC-SHA256 signature signed with the `client_secret`. The signature can include the concatenated ID and `issued_at` value, which you can use to verify that the identity URL hasn’t changed since the server sent it. |
| `sfdc_community_url` | Yes. | The URL of the Experience Cloud site. |
| `sfdc_community_id` | Yes. | The user’s Experience Cloud site ID. |
| `state` | No. | The state requested by the client. This value is included only if the `state` parameter is included in the original query string. |
| `token_type` | Yes. | A `Bearer` token type, which is used for all responses that include an access token. |

## Server-Side Callback Handler Processes the Token Response

To get the access token, the callback handler processes the response and then returns the access token and state to the browser, along with user data, tokens, and session data. As a best practice, we recommend that you configure your server to store the access token, create a session for the app, and return the session to the app, instead of returning the access token. As the developer, you’re in full control of creating the session, storing the access token, and managing the logged-in state, so your specific implementation is up to you.

Here’s an example of a successful response in the browser console log.

```
{
"success":true,
"state":"https://MyExperienceCloudSite.my.site.com/",
"errMsg":"null",
"access_token":"00*******"
}
```

## App Creates the User’s Session

The app receives the access token response and creates the user’s session.

## The User Is Logged In and Performs an Action in the App

The end user is now logged in, and they perform an action in your app that requires access to Salesforce data. For example, they click a button to view their order history, which is stored in Salesforce.

![Note](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/images/icon_note.png)

Note When you set up your external client app or connected app for the Authorization Code and Credentials Flow, you set the Permitted Users policy to **Admin-approved users are pre-authorized** and configure which profiles or permission sets can access the app. With this policy, users access the app without authorizing it, so they don’t get an authorization screen prompting them to let the app access their data.

## App Makes an Authenticated Call to a Salesforce Endpoint

To access the user’s Salesforce data, your app uses the access token to make an authenticated call to a protected Salesforce endpoint, such as a Salesforce API.

## User Can Access Salesforce Data

The user can now access protected Salesforce data in your app. For example, they can see their order history. From the user’s perspective, the entire process from logging in to accessing their data happened without ever requiring them to leave the app.