---
schema_version: "1"
id: d97e4b6d15645f7ae22659c1ecde3aa49d9bbc21935b4ede4690c4c1401046a8
title: "Headless Identity APIs: Headless Registration Flow for Public 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_public_clients.md
canonical_url: https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_headless_registration_public_clients.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: d9510eebebb9da3707e873163caa15692bc90b829dc29741be47e5eadecef096
description: For apps that can’t keep confidential information, such as single-page apps, 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 Public Clients

For apps that can’t keep confidential information, such as single-page apps, 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>

This help content describes how to set up the flow and how it works. To set up an end-to-end example implementation, see the Headless Identitly Implementation Guide.

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 single-page web 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.

For security, we strongly recommend that you implement the Proof Key for Code Exchange (PKCE) extension for this flow.

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. ![Sequence diagram showing headless registration for single-page 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_spa_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 the 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. Again, it’s up to you how you want this form to look. (6)
- The user receives their OTP and enters it in your verification form. (7)
- Your app then initializes the Authorization Code and Credentials Flow with an authorization code request. The request includes the OTP and the 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. 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 callback endpoint. (1)
- Your callback endpoint extracts the code and other parameters from the 302 redirect. It returns this information to your app. (11)
- Your app initiates the code exchange via a POST request to the token endpoint. (12)
- From the token endpoint, Salesforce returns an access token response to your app. (13)
- Your app processes the token response and creates the user’s session. (14)
- The user is now registered and logged in. 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)

This flow requires a server-side endpoint that can handle the 302 redirect and return the authorization code and other parameters to your app. For implementations where you complete the code exchange in your browser, you can use the /services/oauth2/echo endpoint. This endpoint automatically parses the 302 redirect, extracts the parameters, and returns them to your app in JSON format. We use the /services/oauth2/echo in the code examples for this flow. For more information, see [OAuth 2.0 Echo Endpoint](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_echo_endpoint.htm&release=264.0.0&type=5 "Use the OAuth 2.0 echo endpoint to simplify development when you configure the Authorization Code and Credentials Flow for public clients, such as single-page apps. You can also use this endpoint for variations of the Authorization Code and Credentials Flow, including headless registration, passwordless login, and guest user flows.").

![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 Public Clients](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_authcodecreds_singlepageapp.htm&release=264.0.0&type=5 "For public clients such as single-page apps or mobile apps, you can set up headless login for customers and partners by using the Authorization Code and Credentials Flow. This flow is built on the OAuth 2.0 Authorization Code grant type. With the Authorization Code and Credentials Flow, you control the front-end login experience in a third-party app. You call Salesforce Headless Login APIs via your Experience Cloud site to handle the back-end work of authenticating users and granting access to protected Salesforce resources. With separate front-end and back-end processes, your users can log in and access Salesforce data without leaving your app. For single-page apps, you use a server-side callback endpoint to extract the authorization code, and you perform the code exchange from the browser via client-side JavaScript.").

## 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 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 headless POST request to the headless registration endpoint (/services/auth/headless/init/registration) on your Experience Cloud site using Asynchronous Java and XML (AJAX).

You can include this header in your registration request.

  
| 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/json`. |

![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 configure Experience Cloud settings for this flow, you see the Require authentication to access this API setting. With this setting enabled, your registration request must include an access token issued to an integration user in an Authorization header. We recommend that you never enable this setting for single-page apps, because they can’t keep information secret. Instead, always enable **Require reCAPTCHA to access this API**.

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="d73715e302">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d73715e305">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d73715e308">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e302 ">
              <code>password</code>
            </td>

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

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e305 ">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="d73715e308 ">
              <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="d73715e302 ">
              <code>recaptcha</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e305 ">
              <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. We strongly recommend that you
                  always enable this setting for public clients.</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="d73715e308 ">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="d73715e302 ">
              <code>recaptchaevent</code>
            </td>

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e308 ">The method you want to use 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="d73715e302 ">
              <code>customdata</code>
            </td>

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e308 ">A JSON object that contains any custom user information that you collect. For
              example, you can include the user’s street address. You determine the structure of
              this object. It gets delivered to the registration handler as a JSON string, which
              you can deserialize into any Apex class structure you want.</td>

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

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

```
POST /services/auth/headless/init/registration? HTTP 1.1
Host: MyExperienceCloudSiteName.my.site.com
Content-Type: application/json

{
 “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 has yet to verify the user’s identity, it doesn’t do anything with the user information yet. Instead, Salesforce 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="d73715e598">Header</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d73715e601">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d73715e604">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Header" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e598 ">
              <code>Auth-Request-Type</code>
            </td>

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e604 ">
              <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="d73715e598 ">
              <code>Auth-Verification-Type</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e601 ">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="d73715e604 ">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="d73715e598 ">
              <code>Uvid-Hint</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e601 ">
              <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="d73715e604 ">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 user flow on your app.</td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e601 ">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="d73715e604 ">Specifies the format of your request, such as <code>application/x-www-form-urlencoded</code>.</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="d73715e735">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d73715e738">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d73715e741">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e735 ">
              <code>client_id</code>
            </td>

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e741 ">&nbsp;</td>

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

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e741 ">
              <p>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. </p>
              <p style="margin-bottom:0;">For this flow, you can use the echo endpoint,
                <samp class="filepath">https://MyExperienceCloudSite.my.site.com/services/oauth2/echo</samp>,
                as your callback endpoint.
              </p>
            </td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e738 ">
              <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="d73715e741 ">A plain UVID value, which is a Version 4 UUID that’s generated and managed
              entirely by your app. 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 user
              flow on your app.</td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e738 ">Only if you’re using PKCE. PKCE is recommended, especially for single-page
              apps.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e741 ">
              <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 the authorization endpoint. This example includes PKCE.

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

reponse_type=code_credentials&
client_id=******&
redirect_uri=https://www.MyExperienceCloudSite.my.site.com/services/oauth2/echon&
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 Validates Credentials and Returns a 302 Redirect to the Callback Endpoint

Salesforce 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. Salesforce then automatically sends the redirect response to the redirect URL, which points to the /services/oauth2/echo callback endpoint in these code examples. During this process, the browser isn’t redirected—everything happens behind the scenes.

Here’s an example URL that the echo callback endpoint receives.

```html
https://MyExperienceCloudSite.my.site.com/services/oauth2/echo?code=aPrxr*******%3D%3D&state=mystate&sfdc_community_url=https%3A%2F%2FMyExperienceCloudSite.my.site.com%&sfdc_community_id=0DBRXXXXXXXXX
```

## Callback Endpoint Extracts Code and Returns It to App

The callback endpoint extracts the authorization code and other data, and sends this information back to your app. Here’s an example of the JSON response from the echo endpoint.

```json
{"code":"aPrxr*******",
"sfdc_community_url":"https://MyExperienceCloudSite.my.site.com",
"sfdc_community_id":"0DBRXXXXXXXXX",
"state":"mystate"}
```

## App Receives Code Response and Performs Code Exchange

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

```html
{"success":true,"state":"https://MyExperienceCloudSite.my.site.com/","sfdc_community_url":"https://MyExperienceCloudSite.my.site.com/vforcesite","sfdc_community_id":"0DBxxxxxxxxxxxx","errMsg":null,"code":"aPrxC1*******"}
```

The browser headlessly requests to exchange the code for an access token.

To avoid exposing the consumer secret to the browser, you must disable the Require Secret for Web Server Flow and Require Secret for Refresh Token Flow settings on your connected app or external client app. With these settings disabled, the consumer secret isn’t required in the authorization request. If possible, we recommend that you perform the code exchange using a server back end. 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.").

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="d73715e1027">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d73715e1030">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d73715e1033">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e1027 ">
              <code>client_id</code>
            </td>

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

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

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

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

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

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e1030 ">Only if you’re using PKCE. We recommend that you always use PKCE when using
              this flow for a single-page app.</td>

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

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

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

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d73715e1033 ">
              <p>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.</p>
              <p style="margin-bottom:0;">For this flow, you can use
                the echo endpoint,
                <samp class="filepath">https://MyExperienceCloudSite.my.site.com/services/oauth2/echo</samp>,
                as your callback endpoint.
              </p>
            </td>

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

Here’s an example token request.

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

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

## Salesforce Grants an Access Token

After validating the app’s credentials, Salesforce returns an access token to the browser. Here’s an example access token response in JSON format.

```json
{
"access_token":"*******************",
"sfdc_community_url":"https://MyExperienceCloudSiteName.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. |

## App Processes Token Response and Creates the User Session

The browser stores the information from the token response and creates the user session. At this point, the user is logged in, and your app calls the Salesforce User Info endpoint to confirm that the login was successful.

![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 Ensure that you complete a full security review of your access token storage. Never store the access token in the browser’s local storage, and avoid storing it in a cookie if possible.

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

Your user is now fully 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. From the user’s perspective, the entire process from logging in to accessing their data happened without ever requiring them to leave the app.