---
schema_version: "1"
id: 7bf59d503592447b986bffad02737df72897283e0048e36d791831cba1723f66
title: "Headless Identity APIs: Headless Registration 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_registration_private_clients.md
canonical_url: https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_headless_registration_private_clients.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: 38226440f5bbd60a6f27d951ced2bf5cde0e5ea0ec03b9bb5a23a989bb682658
description: For apps that are able to keep confidential information, such as web apps with a client-server architecture, you can set up headless registration for customers and partners using the Headless Registration Flow. The Headless Registration Flow extends the Authorization Code and Credentials Flow, which is built on the OAuth 2.0 Authorization Code grant type. With this flow, you control the front-end user registration experience in a third-party app. You call Salesforce Headless Registration API via your Experience Cloud site to create users, log them in, and give them access to Salesforce resources. By separating these two processes, your users can register for your app and access Salesforce data without leaving the app.
products:
  - Security
  - Cross Cloud
release: "264"
---
# Headless Identity APIs: Headless Registration Flow for Private Clients

For apps that are able to keep confidential information, such as web apps with a client-server architecture, you can set up headless registration for customers and partners using the Headless Registration Flow. The Headless Registration Flow extends the Authorization Code and Credentials Flow, which is built on the OAuth 2.0 Authorization Code grant type. With this flow, you control the front-end user registration experience in a third-party app. You call Salesforce Headless Registration API via your Experience Cloud site to create users, log them in, and give them access to Salesforce resources. By separating these two processes, your users can register for your app and access Salesforce data without leaving the app.

### 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>

Here’s an example use case for the Headless Registration Flow. You work for a travel company that manages customer information in Salesforce. It’s important for you to have complete control over the user experience in the app. You also want to retain more customers by encouraging them to register for your app, which requires identity services. Because your company already uses Salesforce, Headless Identity is the way to go. You build a traditional client-server app and configure the Headless Registration Flow. When new users sign up for your app, they’re greeted with your customized registration experience. They register, verify their identity, and access Salesforce data without interacting directly with Salesforce.

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=sf.headless_identity_email_template_allowlist.htm&language=en_US).

Before setting up this flow, configure the necessary settings and access policies on your connected app or external client app See [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.") or [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)

Here’s an overview of the flow.![Headless registration for client-server apps](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/identity/images/headless_registration_clientserver_diagram.png)

- A user opens your app and clicks Register. (1)
- In your app, you natively display a registration form to collect user data. You design this form and customize the information that you want to collect. (2)
- The user enters their information in the app. For example, they enter their new username, password, and first name. (3)
- Your app submits the user information to the Headless Registration API /services/auth/headless/init/registration endpoint on your Experience Cloud site. (4)
- Salesforce receives the user information and queues it to be processed later. Salesforce returns a success message that includes a registration request ID to your app. (5a)
- Salesforce then sends an email or an SMS text message containing a one-time password (OTP) to the user. (5b)
- In your app, you natively display an OTP verification form. You choose how you want this form to look. (6)
- The user receives their OTP and enters it in the verification form. (7)
- Your app then initializes the Authorization Code and Credentials Flow with an authorization code request to Headless Login API. The request includes the OTP and a request ID, along with other parameters. (8)
- Salesforce verifies the request ID and OTP. It retrieves the queued user data that it stored earlier and calls the headless registration handler. The headless registration handler creates a user in Salesforce. (9)
- Salesforce returns a 302 redirect to a preconfigured URL containing the authorization code. The 302 redirect is processed within the browser, and the response is delivered headlessly to the preconfigured callback handler on your server. (10)
- Your server-side callback handler extracts the code and other parameters from the 302 redirect. It then initiates the code exchange via a POST request to the token endpoint. (11)
- From the token endpoint, Salesforce returns an access token response to the server-side callback handler. (12)
- 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, depending on your app design and security posture. (13)
- The browser receives the logged in response and creates the user’s session. (14)
- The user is now logged in, and they perform an action in your custom app that initiates a request for Salesforce data. For example, they click a button to access their travel booking history, which is stored in the Salesforce Experience Cloud site. (15)
- Your custom app makes an authenticated request to a protected Salesforce endpoint, such as a Salesforce API. (16)
- The customer can now access their protected data in your custom app. For example, they can see their travel booking history. (17)

![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 Because the Headless Registration Flow is built on the Authorization Code and Credentials Flow, many of the steps are similar. For a detailed overview of how you can use JavaScript and Apex to configure the Authorization Code and Credentials Flow, see [Headless Identity APIs: Authorization Code and Credentials Flow for Private Clients](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_authorization_code_credentials_flow.htm&release=264.0.0&type=5 "For private clients, such as client-server apps, you can set up headless login for customers and partners by using the Authorization Code and Credentials Flow, which is built on the OAuth 2.0 Authorization Code grant type.").

## User Opens Third-Party App and Clicks Register

Your user opens your app and clicks a registration link, or they click a link to access a resource that requires registration.

## Your App Displays a Registration Form

In your app, you natively display a registration form to collect user data. You control everything about this form, including its look, feel, and the user information that you want to collect.

There are a few considerations about what information you want to gather from users. When your app submits user information to Headless Registration API, Salesforce checks for an email address, username, last name, and password. You can collect this information from users or autogenerate it, but it must be included in your POST request. When deciding what information to include, make sure to collect an email address or phone number so that the user can verify their identity.

## User Enters Their Information

In your app, the user enters their information in your registration form.

## Your App Headlessly Sends the User Information to Headless Registration API

From the browser, your app sends a POST request to the headless registration endpoint (/services/auth/headless/init/registration) on your Experience Cloud site using Asynchronous Java and XML (AJAX).

Include these headers in your registration request.

  
| Header | Required? | Description |
| --- | --- | --- |
| `Authorization: Bearer` | This header is required if you enable **Require authentication to access this API** on the Experience Cloud Login & Registration page. We strongly recommend that you always enable this setting for private clients. | Contains 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 `user_registration_api` scope to your connected app or external client app, or pass it as a parameter during your flow. |
| `Content-Type` | No. If you’re using Postman to build and test your flow, it sometimes adds this header. Verify that it’s correct by checking the hidden headers. | Specifies the format of your request, such as `application/json`. |

Include these parameters in the request body.

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small ">
        <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="d9098e290">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d9098e293">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d9098e296">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e290 ">
              <code>password</code>
            </td>

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e296 ">The user’s password. The password is subject to any password policies
              configured for the profile or org.</td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e293 ">Yes. Even if you don’t collect this information from the user, you must
              autogenerate it and pass it in the <code>userdata</code> parameter.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e296 ">
              <p>Contains all required user information. At minimum, Salesforce requires this
                information in the <code>userdata</code> parameter.</p>
              <ul>
                <li><code>username</code></li>

                <li><code>lastName</code></li>

                <li><code>email address</code></li>

              </ul>
            </td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e293 ">
              <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="d9098e296 ">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="d9098e290 ">
              <code>recaptchaevent</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e293 ">
              <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="d9098e296 ">
              <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="d9098e290 ">
              <code>verificationmethod</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e293 ">
              <p>No. If you don’t include this parameter, Salesforce defaults to verifying the
                user’s identity with email.</p>
              <p style="margin-bottom:0;">If you include this parameter, include an
                <code>Auth-Verification-Type</code> header in your request to the
                authorization endpoint. The value in this header must match the value specified
                here in the <code>verificationmethod</code> parameter.
              </p>
            </td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e296 ">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="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e290 ">
              <code>customdata</code>
            </td>

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e296 ">Contains any custom user information that you collect. For example, you can
              include the user’s street address.</td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e293 ">
              <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.</p>
            </td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e296 ">The custom email template developer name. This parameter can include only an
              email template from the allowlist.</td>

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

Here’s an example POST request. In this example, the Experience Cloud settings are configured to require both authentication and reCAPTCHA, so the request includes an access token and a reCAPTCHA token.

```
POST /services/auth/headless/init/registration? HTTP 1.1
Host: MyDomainName.my.site.com
Content-Type: application/json
Authorization: Bearer **************
{
 “userdata”: {
  “firstName”: “Janice”
   “lastName”: “Edwards”
   “email”: “janice.edwards@example.com”
   “username”: “jedwards@myapp.com”
    }
 “customdata”: {
   {”mobilePhone”=”<mobile phone number>”
   }
 “password”: “*******”
 “recaptcha”:”***********”
 “verificationmethod”: “email”
“emailtemplate”: “unfiled$public/SalesNewCustomerEmail”
}
```

## Salesforce Receives the Information and Returns a Request Identifier

Salesforce receives the user information. Because Salesforce hasn’t verified the user’s identity, it queues this information to be processed later.

If the information in the POST request is valid, Salesforce returns a success message to the app. This message includes a registration request identifier, which is important later in the flow. Here’s an example success message.

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

## Salesforce Sends a One-Time Password to the User

Immediately after Salesforce receives the user data and sends a success message to the app, it sends a one-time password (OTP) via email or SMS, depending on the user’s verification method.

## Your App Natively Displays a Verification Form

When you receive the success message, you natively display an OTP verification form in your app. Again, the look and feel of the verification experience is entirely up to you.

## User Enters OTP in Verification Form

Your user receives the OTP via email or SMS and enters it in your verification form.

## Your App Initializes the Authorization Code and Credentials Flow

When the user proves their identity, the app immediately initializes the Authorization Code and Credentials Flow with a request to Headless Login API.

Include these headers in the authorization request

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small ">
        <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="d9098e586">Header</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d9098e589">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d9098e592">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Header" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e586 ">
              <code>Auth-Request-Type</code>
            </td>

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

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e592 ">
              <p>A Basic header that identifies the registration request so that Salesforce can
                link the request to the user’s stored data. You must include the request identifier
                provided by Salesforce and the OTP used to verify the user’s identity. </p>
              <p style="margin-bottom:0;">Append
                these values to each other in the format <code>&lt;request
                    ID:OTP&gt;</code> and Base64-encode the resulting value. The entire header value
                looks something like <code>Basic &lt;base64-encoded request
                    ID:OTP&gt;</code>.</p>
            </td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e589 ">No. If you’re using Postman to build and test your flow, it sometimes adds this
              header. Verify that it’s correct by checking the hidden headers.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e592 ">Specifies the format of your request, such as <code>application/x-www-form-urlencoded</code>.</td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e589 ">Required if you specified an identity verification method in your initial
              registration request. The value of this header must match the value in the <code>verificationmethod</code> body parameter from your request
              to the <code>/services/auth/headless/init/registration</code> endpoint.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e592 ">Specifies 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="d9098e586 ">
              <code>Uvid-Hint</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e589 ">
              <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 (UVID) tied to a guest user’s identity. By passing the UVID 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 UVID in a header, you can also pass the plain UVID value in
                the request body.</p>
            </td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e592 ">A JWT-based access token containing a UVID 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 UVID, you must enable your connected app or
              external client 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 ">
        <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="d9098e723">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d9098e726">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d9098e729">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e723 ">
              <code>client_id</code>
            </td>

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

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

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

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

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e729 ">The URL where users are redirected after a successful authentication. The
              redirect URI must match one of the values in the connected app or external client
              app Callback URL field. Otherwise, the approval fails. This value must be URL
              encoded.</td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e726 ">
              <p>No. If you implement the guest user flow on your app, you can optionally use
                this parameter to pass in a UVID 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 UVID in the request body, you can also pass it
                in a JWT-based token with a UVID via the <code>UVID-Hint</code> header.</p>
            </td>

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e729 ">
              <p>Required if using the PKCE extension. 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 base64url-encoded as defined in <a href="https://tools.ietf.org/html/rfc4648#section-5" target="_blank"><samp class="filepath">https://tools.ietf.org/html/rfc4648#section-5</samp></a>.
              </p>
              <p>This parameter is required if a <code>code_verifier</code> is specified in the token request.</p>
              <ul>
                <li>If the <code>code_challenge</code> value is provided
                  in the authorization request and a <code>code_verifier</code> value is provided in the token request, Salesforce
                  compares the <code>code_challenge</code> to the <code>code_verifier</code>. If the <code>code_challenge</code> is invalid or doesn’t match, the login fails with the
                  <code>invalid_request</code> error code.
                </li>
                <li>If the <code>code_challenge</code> value is provided
                  in the authorization request, but a <code>code_verifier</code> value isn’t provided in the token request, the login
                  fails with the <code>invalid_grant</code> error
                  code.</li>
              </ul>
            </td>

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

Here’s an example request to Headless Login API, including PKCE.

```
POST /services/oauth2/authorize? HTTP 1.1
Host: MyDomainName.my.site.com
Auth-Request-Type: user-registration
Auth-Verification-Type: email
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <base64-encoded request ID:OTP>

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

## Salesforce Verifies the Request, Retrieves the User Data, and Creates the User

Salesforce receives the authorization request and verifies the request ID and OTP. Salesforce uses this information to retrieve the queued user data and call the headless registration handler configured in your Experience Cloud site. The Apex handler creates the user in Salesforce and links them to an account.

## Salesforce Returns a 302 Redirect to a Preconfigured URL Containing the Code

Salesforce returns an HTTP 302 redirect to a preconfigured URL containing the authorization code. The 302 redirect is processed within the browser, and the response is delivered headlessly to the redirect URL, which is a preconfigured callback endpoint on your server. Here’s an example 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
```

## 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.

For the access token request, you can use only a POST request—GET requests aren’t supported. There are no required headers for this request, but you can include a `Content-Type` header.

  
| Header | Required? | Description |
| --- | --- | --- |
| `Content-Type` | No. If you’re using Postman to build and test your flow, it sometimes adds this header. Verify that it’s correct by checking the hidden headers. | Specifies the format of your request, such as `application/x-www-form-urlencoded`. |

Include these parameters in the request body.

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small ">
        <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="d9098e981">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d9098e984">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d9098e987">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e981 ">
              <code>client_id</code>
            </td>

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

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

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

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

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e987 ">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="d9098e981 ">
              <code>code_verifier</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e984 ">Required if using the PKCE extension.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e987 ">
              <p>Specifies 128 bytes of random data with high entropy to make guessing the
                <code>code</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://tools.ietf.org/html/rfc4648#section-5" target="_blank"><samp class="filepath">https://tools.ietf.org/html/rfc4648#section-5</samp>.</a>
              </p>
              <ul>
                <li>If the <samp class="parmname">code_verifier</samp> value is provided in the token
                  request and a <samp class="parmname">code_challenge</samp> value is in the authorization
                  request, Salesforce compares the <samp class="parmname">code_verifier</samp> to the
                  <samp class="parmname">code_challenge</samp>. If the <samp class="parmname">code_verifier</samp>
                  is invalid or doesn’t match, the login fails with the <code>invalid_grant</code> error code.
                </li>
                <li>If the <samp class="parmname">code_verifier</samp> value is provided in the token
                  request, but a <samp class="parmname">code_challenge</samp> value isn’t provided in the
                  authorization request, the login fails with the <code>invalid_grant</code> error code.</li>
              </ul>
            </td>

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e987 ">
              <p>The expected format of the response. Salesforce supports these formats.</p>
              <ul>
                <li><code>urlencoded</code></li>
                <li><code>json</code> (default)</li>
                <li><code>xml</code></li>
              </ul>
            </td>

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e987 ">The type of validation that the connected app or external client 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="d9098e981 ">
              <code>redirect_uri</code>
            </td>

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d9098e987 ">The URL where users are redirected after a successful authentication. The
              redirect URI must match one of the values in the connected app or external client
              app Callback URL field. This value must be URL encoded.</td>

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

Here’s an example token request.

```
POST /services/oauth2/token HTTP 1.1
Host: MyDomainName.my.site.com
Content-Type: application/x-www-form-urlencoded

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

## Salesforce Grants an Access Token

Salesforce validates the token request and returns an access token response to the server-side callback handler. Here’s an example access token response in JSON format.

```json
{
"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.

  
| Parameter | Required? | Description |
| --- | --- | --- |
| `access_token` | Yes. | OAuth token that a connected app or external client 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. |   |
| `instance_url` | Yes. | A URL indicating the instance of the user’s org. For example: `https://yourInstance.salesforce.com/`. |
| `issued_at` | Yes. | Time stamp 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 connected app or external client 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. |

## Callback Handler Processes Token Response and Returns Parameters to App

The server-side callback handler gets the access token from the response. The server-side callback handler 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 Processes Token Response and Creates the User Session

The app receives the token response, processes it, and creates the user session.

## User Is Registered and Performs an Action in the App

Your user is now registered and logged in. They perform an action in your app that requires access to Salesforce data. For example, they click a button to view their travel booking 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 connected app or external client 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 travel booking history.