---
schema_version: "1"
id: a3bf86e949d8b9bcb419e78f827bdf084342d526bdb9d503726cbf024a71f84b
title: "OAuth 2.0 for First-Party Applications: 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_auth_challenge_registration.md
canonical_url: https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_auth_challenge_registration.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: 76b7e7e6b082e9bcc01c97dcc425f57a0326dc5cbb6d0d01adda0153af78fa0d
description: To set up a headless user registration process for an off-platform app developed by your company, use this flow, which implements the OAuth 2.0 for First-Party Applications draft standard protocol. This flow is supported only for private clients, such as client-server apps. With this flow, you can entirely control the front-end registration experience in your first-party app while Salesforce handles the backend work of authenticating users and granting access to protected resources. This flow is supported only for private clients, such as client-server apps, and is supported only for external users.
products:
  - Security
  - Cross Cloud
release: "264"
---
# OAuth 2.0 for First-Party Applications: Headless Registration Flow for Private Clients

To set up a headless user registration process for an off-platform app developed by your company, use this flow, which implements the OAuth 2.0 for First-Party Applications draft standard protocol. This flow is supported only for private clients, such as client-server apps. With this flow, you can entirely control the front-end registration experience in your first-party app while Salesforce handles the backend work of authenticating users and granting access to protected resources. This flow is supported only for private clients, such as client-server apps, and is supported only for external users.

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

To set up headless registration for a private client, you can also use [this version](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_headless_registration_private_clients.htm&type=5&language=en_US) of the Authorization Code and Credentials Flow, which implements Headless Identity APIs. Both flows accomplish the same use case—registration for an app outside of the Salesforce platform. But there are a few key differences to keep in mind.

 
| OAuth For First-Party APPS | Headless Identity APIS |
| --- | --- |
| Supported only for private clients. | Supported for public and private clients. |
| Conforms to the [OAuth 2.0 for First-Party Applications draft standard protocol](https://www.ietf.org/archive/id/draft-parecki-oauth-first-party-apps-00.html). | Proprietary Salesforce flow that's built on top of the OAuth 2.0 standard. |
| Supported only for the Salesforce external client app framework. Also, the only way to configure external client app settings for this flow is via Metadata API. | Supported for both the Salesforce external client app and connected app frameworks. |
| For security, this flow always requires a client attestation JWT. Salesforce uses the client attestation JWT to validate that the app was developed by your company. | For security, requires either authentication or reCAPTCHA, but not a client attestation JWT. |

Before setting up this flow, complete these steps.

- [Complete prerequisites for headless identity](https://help.salesforce.com/s/articleView?id=xcloud.headless_identity_prerequisites.htm&release=264.0.0&type=5 "Before you get started with a Headless Identity implementation for your off-platform apps, cross off these prerequisites in Salesforce.").
- [Generate a client attestation JWT](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_auth_challenge_generate_jwt.htm&release=264.0.0&type=5 "When using headless identity flows that implement the OAuth 2.0 for First-Party Applications draft standard, use a client attestation JWT to prove that apps sending requests to Salesforce are first-party apps created by your company.").
- [Configure a Salesforce external client app](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_eca_auth_challenge.htm&release=264.0.0&type=5 "To develop headless identity flows that use the OAuth 2.0 for First-Party Applications draft standard, configure an external client app. For these flows, you must configure your external client app via Metadata API. Use these steps to configure an app for headless username-password login, passwordless login, and registration.").
- [Configure Experience Cloud settings](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_auth_challenge_experience_settings.htm&release=264.0.0&type=5 "Before you build headless username-password login, passwordless login, and registration flows using the OAuth 2.0 for First-Party Applications draft protocol, configure Experience Cloud settings on the Login & Registration page.").

Here's an overview of how the flow works.

- Step 1: An end user opens your first-party app and clicks Register.
- Step 2: 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.
- Step 3: The user enters their information in your app For example, they enter their username, password, and first name.
- Step 4: Your app mints a client attestation JWT. It also generates parameters for the Proof Key for Code Exchang (PKCE) extension.
- Step 5: To initialize registration, your app submits the user information to the services/oauth2/v1/authorization\_challenge endpoint on your Experience Cloud site. The request includes a client attestation JWT.
- Step 6: To confirm that your first-party app sent the request, Salesforce validates the client attestation JWT, and then validates the other parameters sent in the request.
- Step 7: When the request is successful, Salesforce returns a response with an `auth_session`. The response indicates that Salesforce initialized registration and sent a one-time password (OTP) to the user.
- Step 8: In your app, you natively display a verification form. You choose how you want this form to look.
- Step 9: The user receives their OTP and enters it in the verification form.
- Step 10: To request an authorization code, your app sends another POST request to the services/oauth2/v1/authorization\_challenge endpoint. The request includes the `auth_session` and the OTP.
- Step 11: If the request is successful, Salesforce returns an authorization code to your app and terminates the `auth_session`.
- Step 12: To exchange the code for an access token, your first-party app sends a request to the /services/oauth2/token endpoint.
- Step 13: Salesforce returns a token response containing the access token.
- Step 14: Your first-party app processes the token response and creates the user's session.
- Step 15: The user is now logged in and they perform an action in your app that initiates a request for Salesforce data.
- Step 16: Your app makes an authenticated request to a protected Salesforce endpoint, such as a Salesforce API.
- Step 17: The user can now access their protected data in your app.

## Step 1: User Opens First-Party App and Clicks Register

A user opens your first-party app and clicks a registration link. Or they click a link to access a resource that requires registration.

## Step 2: First-Party App Displays Registration Form

In your first-party app, you natively display a registration form to collect information about the user. 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 the authorization challenge endpoint, 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.

## Step 3: User Enters Their Information

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

## Step 4: First-Party App Mints a Client Attestation JWT and Generates `code_verifier` and `code_challenge` Values for PKCE

The app [mints a client attestation JWT](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_auth_challenge_generate_jwt.htm&release=264.0.0&type=5 "When using headless identity flows that implement the OAuth 2.0 for First-Party Applications draft standard, use a client attestation JWT to prove that apps sending requests to Salesforce are first-party apps created by your company.").

The app also generates values for the PKCE parameters used to verify the authorization code.

![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 We strongly recommend that you always implement PKCE for this flow. Otherwise, you don't get its security benefits.

For more information on PKCE, see the specificationRFC 7636: Proof Key for Code Exchange by OAuth Public Clients provided by the [Internet Engineering Task Force (IETF)](https://datatracker.ietf.org/doc/rfc7636/).

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

## Step 5: App Sends Initial Request to the Authorization Challenge Endpoint

From the browser, your app sends a POST request to the services/oauth2/v1/authorization\_challenge endpoint on your Experience Cloud site.

Include this header in your request if necessary.

Initial Registration Request: Headers   
| Header | Required? | Description |
| --- | --- | --- |
| `Authorization: Bearer` | Required if you enable **Require authentication to access this API** in the headless registration section on the Experience Cloud Login & Registration page. | 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. |

Include these parameters in the request body.

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

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

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

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d24446e422 ">
              <p>Required if these conditions apply to you:</p>
              <ul>
                <li>You enabled <strong> Require reCAPTCHA to access this API</strong> for headless
                  registration in your Experience Cloud Login &amp; Registration settings.</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="d24446e425 ">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="d24446e419 ">
              <code>recaptchaevent</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d24446e422 ">
              <p>Required if these conditions apply to you:</p>
              <ul>
                <li>You enabled <strong> Require reCAPTCHA to access this API</strong> for headless
                  registration in your 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="d24446e425 ">
              <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="d24446e419 ">
              <code>client_assertion</code>
            </td>

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d24446e425 ">The client attestation JWT that you generated, signed by the certificate
              configured for your external client app.</td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d24446e422 ">No. If you don’t include this parameter, Salesforce defaults to verifying the
              user’s identity with email.</td>

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

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

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d24446e422 ">
              <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="d24446e425 ">The custom email template developer name. This parameter can include only an
              email template from the allowlist.</td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d24446e422 ">Required if you required PKCE for your external client app. For this flow's
              security features to work correctly, we strongly recommend that you always require
              PKCE.</td>

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

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

Here's an example initial registration request.

```
POST /services/oauth2/v1/authorization_challenge? HTTP 1.1
Host: MyExperienceCloudSite.my.site.com
{
    "userdata": {
        "firstname": "Janice"
        "lastname": "Edwards"
        "email": "janice.edwards@example.com"
        "username": "jedwards@myapp.com"
        }
    "customdata": {
        "mobilePhone"="<mobile phone number>"
        }
    "password":"*********"
    "recaptcha": "*******"
    "login_type": "email"
    "emailtemplate": "unfiled$public/SalesNewCustomerEmail"
    "client_assertion": "Y2xpZW50YXNzZXJ0aW9u..."
}
```

## Step 6: Salesforce Validates the Request

Salesforce first attempts to validate the client attestation JWT by validating that the signature passed in the `client_asssertion` parameter matches the signature for the certificate configured for the external client app.

If the client attestation JWT isn't valid, Salesforce returns an `invalid_attestation` error and you must resubmit the request with all of the parameters you originally submitted. Here's an example error response.

If the client attestation JWT is valid, but there are other issues with the request, Salesforce returns an error response specifying what was wrong with the request. The response also includes an `auth_session` parameter that remains valid for 5 minutes after it's issued. During the timeframe while the `auth_session` is valid, you can use it to resubmit the request. In the corrected versions that you resubmit, include only the corrected values for the parameters that caused the request to fail. You must also resubmit the `password` with each request because Salesforce doesn't store it. But for other parameters, if they didn't cause the request to fail, you can leave them out. They're already represented by the `auth_session`.

![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 reCAPTCHA parameters don't get linked to the `auth_session`, but you can resubmit the request without them, unless they caused the request to fail.

For example, if your client attestation JWT is valid but the request fails because the username was incorrect, resubmit a request that includes only the `auth_session`, `username`, and `password`.

## Step 7: Salesforce Sends an OTP to the User

If the request is successful, Salesforce still returns an error response because it can't yet grant the authorization code. But this time, the error response indicates that login was initialized and that Salesforce sent an OTP to the user's email address or phone number. To confirm that the request was successful, look out for the error code `login_initialized` and the state `otp_sent`. The response also includes an `auth_session` parameter, which is important for the next step.

Here's an example response.

```
HTTP/1.1 403 Forbidden
Content-Type: application/json
Cache-Control: no-store

{
  "error": "authorization_required",
  "auth_session": "uY29tL2F1dGhlbnRpY",
  "error_code": "login_initialized",
  "login_status": {
    "type": "SMS",
    "state": "otp_sent",
    "displayData": "+120******58"
   }
}
```

## Step 8: Your App Natively Displays a Verification Form

In your first-party app, you display a verification form where the end user can enter their OTP. The look and feel of this form are entirely up to you.

## Step 9: User Enters OTP in Verification Form

The user receives the OTP and enters it in the verification form in your first-party app.

## Step 10: Your App Requests an Authorization Code

To request an authorization code, your app sends the `auth_session` and the OTP that the user entered to the authorization challenge endpoint using another POST request to the services/oauth2/v1/authorization\_challenge This request has no required headers. Include these parameters in the request body.

Authorization Code Request: Body Parameters   
| Parameter | Required? | Description |
| --- | --- | --- |
| `auth_session` | Yes. | Represents the login attempt. Use the `auth_session` value that you received in the response from your first request to the authorization challenge endpoint. Make sure to use the `auth_session` from the request that indicated that login was initialized and the OTP was sent. |
| `login_otp` | Yes. | The OTP that the end user entered in your app's verification form. |

Here's an example request.

```
POST /authorize HTTP/1.1
Host: MyExperienceCloudSite.my.site.com

auth_session=uY29tL2F1dGhlbnRpY*
login_otp=<otp_from_sms>
```

## Step 11: Salesforce Returns an Authorization Code

If the OTP is correct and the `auth_session` request is valid, Salesforce returns an authorization code and terminates the `auth_session`. Here's an example authorization code response.

```
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store

{
  "authorization_code": "uY29tL2F1d******"
}
```

## Step 12: Your App Exchanges the Authorization Code for an Access Token

After you get the authorization code, your app sends a request to the Salesforce token endpoint.

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

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

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

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

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

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

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

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

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d24446e916 ">The URL where users are redirected after a successful authentication. The
              redirect URI must match one of the values in the 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="d24446e910 ">
              <code>grant_type</code>
            </td>

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d24446e916 ">The type of validation that the app can provide to prove it’s a safe visitor.
              For this 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="d24446e910 ">
              <code>code_verifier</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d24446e913 ">Required if you required PKCE for your external client app. For this flow's
              security features to work correctly, we strongly recommend that you always require
              PKCE.</td>

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

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

Here's an example token request.

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

code=********&
client_id=**********&
client_secret=*********&
redirect_uri=<callback_URL>&
grant_type=authorization_code&
code_verifier=*******
```

## Step 13: Salesforce Grants an Access Token

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

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

The access token response contains these parameters.

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

## Step 14: App Creates the User’s Session

Your first-party app processes the token response and creates the user's session.

## Step 15: 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 external client app or connected app for the Authorization Code and Credentials Flow, you set the Permitted Users policy to **Admin-approved users are pre-authorized** and configure which profiles or permission sets can access the app. With this policy, users access the app without authorizing it, so they don’t get an authorization screen prompting them to let the app access their data.

## Step 16: 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.

## Step 17: 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.