---
schema_version: "1"
id: 747e1bba76d04476d77fc75b7e484104ce8ab2d8c87681e8e02db8cbf9e9ebcd
title: "Headless Identity APIs: Headless Guest 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_guest_public_clients.md
canonical_url: https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_headless_guest_public_clients.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: 00fc236b8a554970ae6cfa0b344e5e3246ea00c5e44db0fe542fe8399415c2ae
description: Some users interact with your off-platform app but don’t log in or register. You can issue identifiers in the form of unique visitor ID (UVIDs) for these unknown visitors with the Headless Guest Flow. If the user decides to log in or register, you can pass the identifier into a named user flow, like a headless login flow. Use guest user identity as a tool for carrying context from guest user sessions to named user sessions. This flow is a variation of the Authorization Code and Credentials Flow.
products:
  - Security
  - Cross Cloud
release: "264"
---
# Headless Identity APIs: Headless Guest Flow for Public Clients

Some users interact with your off-platform app but don’t log in or register. You can issue identifiers in the form of unique visitor ID (UVIDs) for these unknown visitors with the Headless Guest Flow. If the user decides to log in or register, you can pass the identifier into a named user flow, like a headless login flow. Use guest user identity as a tool for carrying context from guest user sessions to named user sessions. This flow is a variation of the Authorization Code and Credentials Flow.

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

Before setting up this flow, complete these steps.

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

For example, you host an ecommerce app outside of the Salesforce platform. You want users to be able to save items to a cart without logging in. You can use the guest user flow to generate a UVID for the user, and you can store the user’s cart information and tie it to the UVID. When the user eventually logs in or registers, you pass the UVID into a headless login or registration flow. Because you have the cart context from the UVID, you can save the user’s items, giving your users a better experience.

The shopping cart example is just one of many possibilities when it comes to the UVID and guest flow. Other possibilities include understanding what makes your users want to sign up for your app and remembering their preferences.

The guest flow and UVID are supported only for JSON Web Token (JWT)-based access tokens. To connect the UVID to a named user, you must configure the named user flow to issue JWT-based access tokens too.

These instructions tell you how to implement the flow for a public client, like a single-page app, that can’t keep confidential information private. Public clients have some extra security considerations. Compared to a private client like a client-server app, they don’t have a private backend to store the consumer secret, which acts as a password to secure the code exchange. With nowhere to store a consumer secret, the app can’t risk leaking it. To replace the role of the consumer secret, you can use the Proof Key for Code Exchange (PKCE) extension instead. This extension protects your app with parameters that only you and Salesforce can verify. We always recommend implementing PKCE for a public client.

Here’s an overview of the guest flow. These steps cover the flow up to the point when the guest user is identified, but not logged in.

![Sequence diagram showing headless guest user flow for public clients](https://sf-zdocs-cdn-prod.zoominsoftware.com/tdta-xcloud-identity-264-0-0-production-enus/699dab6f-8f1a-4662-b24f-6521d5b747f7/identity/images/headless_guest_public_clients.png)

- The unknown visitor arrives at the app or performs an action like clicking a button (1).
- The app looks for a UVID, and if it can’t find one, it generates a value.
- If you’re using the Proof Key for Code Exchange (PKCE) extension, which we strongly recommend, the app generates PKCE parameters.
- To get an authorization code, your app headlessly sends the UVID to the Salesforce authorization endpoint (`services/oauth2/authorize`) in a GET or POST request.
- Salesforce validates the UVID and returns a 302 redirect to a preconfigured URL containing the authorization code. The redirect is processed within the browser, and the response is delivered to the callback endpoint.
- The callback endpoint extracts the authorization code and returns it to your app.
- Your app receives the authorization code and initiates a code exchange by sending the code and other parameters in a POST request to the Salesforce token endpoint (`services/oauth2/token`).
- Salesforce validates the request and returns a guest JWT-based access token with the UVID in the subject claim.
- Your app processes the response and creates a guest session, persisting the UVID value.
- The end user now has a guest session keyed to the UVID value returned in the access token.

Like other variations of the Authorization Code and Credentials Flow, for a public client, this flow requires a callback endpoint that can handle the 302 redirect and return the authorization code and other parameters to your app. If you do the code exchange in your browser, you can use the Salesforce `/services/oauth2/echo` endpoint. It automatically parses the 302 redirect, extracts the parameters, and returns them to your app in JSON format. We use the echo endpoint in the code examples for this flow.

## Unknown End User Arrives at Your App

The flow starts when an end user visits your app. You can also configure it to start when the user performs an action, such as saving an item to a cart.

## App Generates a UVID

Your app tries to find a UVID associated with this user. For example, it looks for browser cookies from any previous visits to the app. If the app can’t find a UVID, it generates one. Salesforce doesn’t play a role in generating the UVID. Its generation, storage, and maintenance are entirely up to you. The only requirement is that the UVID must be a Version 4 universally unique identifier (v4 UUID).

## App Generates PKCE Parameters

If you’re using PKCE, your app generates `code_verifier` and `code_challenge` parameters.

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

## App Exchanges the UVID for an Authorization Code

Your app headlessly sends a GET or POST request to the Salesforce authorization endpoint on your Experience Cloud site. The request contains the UVID and other parameters to identify the app and specify the type of request.

You have two options for how you send the UVID in this request. You can either send a plain UVID value, or send a JWT-based access token with the UVID minted into it. For example, if you have a JWT-based access token from a previous session, sending the token to the authorization endpoint is an easy way to reuse it without specifically parsing it for the UVID.

Include these headers in your request.

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e236 ">Required if you don’t send the UVID in the request body. You must always include a
              UVID—whether it’s sent in the header or in the request body.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e239 ">
              <p>Contains either the UVID as a plain value or a JWT-based access token with a UVID
                minted into it.</p>
              <p>If you send the UVID as a plain value, include a <code>UVID</code> prefix before the value so that the request is formatted
                as <code>Uvid-Hint: UVID &lt;UVID value&gt;</code>.</p>
              <p style="margin-bottom:0;">If you send
                a JWT-based access token with a UVID, include a <code>JWT</code>
                prefix before the value, such as <code>Uvid-Hint: JWT &lt;access
          token containing UVID&gt;</code>.</p>
            </td>

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e239 ">Specifies the type of request you want to make to Salesforce. For headless
              passwordless login, this value must be set to <code>guest</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 " summary="Authorization Request: Body Parameters">
        <caption>Authorization 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="d88217e319">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d88217e322">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d88217e325">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e319 ">
              <code>uvid_hint</code>
            </td>

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e322 ">Required if you don’t include the UVID in the header.</td>

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e325 ">
              <p>Contains either the UVID as a plain value or a JWT-based access token with a UVID
                minted into it.</p>
              <p>If you send the UVID as a plain value, include a <code>UVID</code> prefix before the value so that the request is formatted
                as <code>uvid_hint=UVID &lt;UVID value&gt;</code>.</p>
              <p style="margin-bottom:0;">If you send a
                JWT-based access token with a UVID, include a <code>JWT</code>
                prefix before the value, such as <code>uvid_hint=JWT &lt;access token
          containing UVID&gt;</code>.</p>
            </td>

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

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

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

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

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

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e325 ">
              <p>The URL where users are redirected after successful authentication. The <code>redirect_uri</code> must match one of the values in the external
                client app or connected app Callback URL field. Otherwise, the approval fails. This value
                must be URL encoded.</p>
              <p style="margin-bottom:0;">For this flow, you can use the echo endpoint, <code>https://MyExperienceCloudSite.my.site.com/services/oauth2/echo</code>, as your callback
                endpoint.</p>
            </td>

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

            <td data-label="Required?" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e322 ">Only if you’re using PKCE, which we always recommend, especially for a public
              client.</td>

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e325 ">
              <p>Permissions that define the type of protected resources an external client app or
                connected app can access. The values that you send in this request must match or be a subset
                of the scopes assigned to your app.</p>
              <p style="margin-bottom:0;">For more information about each scope and its purpose,
                see <a href="https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_tokens_scopes.htm&amp;type=5&amp;language=en_US" target="_blank">OAuth Tokens and Scopes</a>.</p>
            </td>

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

Check out these example authorization requests, which all implement PKCE.

Here’s an example request where the UVID is passed as a plain value in the request header.

```
POST /services/oauth2/authorize? HTTP 1.1
Host: MyExperienceCloudSite.my.site.com
Uvid-Hint: UVID abcd-1234-efgh
Auth-Request-Type: guest

response_type=code_credentials&
client_id=***********&
redirect_uri=https://www.MyExperienceCloudSite.my.site.com/services/oauth2/echo&
code_challenge=********&
scope=openid
```

In this example, the UVID is passed in a JWT-based access token in the header.

```
POST /services/oauth2/authorize? HTTP 1.1
Host: MyExperienceCloudSite.my.site.com
Uvid-Hint: JWT **************
Auth-Request-Type: guest

response_type=code_credentials&
client_id=***********&
redirect_uri=https://www.MyExperienceCloudSite.my.site.com/services/oauth2/echo&
code_challenge=********&
scope=openid
```

Here’s an example where the UVID is passed as a plain value in the request body.

```
POST /services/oauth2/authorize? HTTP 1.1
Host: MyExperienceCloudSite.my.site.com
Auth-Request-Type: guest

uvid_hint=UVID abcd-1234-efgh&
response_type=code_credentials&
client_id=***********&
redirect_uri=https://www.MyExperienceCloudSite.my.site.com/services/oauth2/echo&
code_challenge=********&
scope=openid
```

## Salesforce Returns a 302 Redirect

Salesforce validates the UVID. If the UVID was passed as a plain value, Salesforce validates its format. If it was passed as a JWT-based access token, Salesforce checks the validity of the token.

Salesforce then returns an HTTP 302 redirect to a preconfigured URL containing the authorization code. If the flow is happening in the browser, the 302 redirect is processed in the browser and Salesforce automatically sends the redirect response to the redirect URL, which is the callback endpoint. Here’s an example preconfigured URL.

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

## Callback Endpoint Sends the Authorization Code to Your App

The callback endpoint extracts the authorization code and returns it to your app. In these code examples, the redirect URL points to the `/services/oauth2/echo` callback endpoint on the Experience Cloud site. This endpoint automatically parses the 302 redirect, extracts the authorization code and other parameters, and returns them to your app in JSON format.

## App Initiates Code Exchange

Your app receives the code response with the authorization and other parameters. It exchanges the code for an access token by sending a headless POST request to the `/services/oauth2/token` endpoint.

Include one header in the request.

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

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

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e576 ">
              <p>Contains either the UVID as a plain value, or a JWT-based access token with a UVID
                minted into it.</p>
              <p style="margin-bottom:0;">For the code exchange, don’t include a prefix for the UVID. For example,
                if you pass the UVID as a plain value, the header is just <code>Uvid-Hint: abcd-1234-efgh</code>. If you pass in a JWT-based access token, it’s <code>Uvid-Hint: &lt;access token containing UVID&gt;</code>.</p>
            </td>

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

Include these parameters in the request body.

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small " summary="Code Exchange: Body Parameters">
        <caption>Code Exchange: 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="d88217e648">Parameter</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d88217e651">Required?</th>
            <th scope="col" class="slds-cell-wrap" style="vertical-align:top;" id="d88217e654">Description</th>
          </tr>
        </thead>
        <tbody>
          <tr class="">
            <td data-label="Parameter" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e648 ">
              <code>code</code>
            </td>

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

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

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

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

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e654 ">
              <p>The URL where users are redirected after a successful authentication. The redirect URI
                must match one of the values in the external client app or connected app Callback URL field.
                Otherwise, the approval fails. This value must be URL encoded.</p>
              <p style="margin-bottom:0;">For this flow, you can use
                the echo endpoint, <code>https://MyExperienceCloudSite.my.site.com/services/oauth2/echo</code>, as your callback
                endpoint.</p>
            </td>

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

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e654 ">The type of validation that the external client app or connected app can provide to
              prove it’s a safe visitor. Because this flow is a variation of 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="d88217e648 ">
              <code>code_verifier</code>
            </td>

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

            <td data-label="Description" class="slds-cell-wrap" style="vertical-align:top;" headers="d88217e654 ">
              <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 that implements PKCE. In this example, the UVID is sent as a plain value.

```
POST services/oauth2/token? HTTP 1.1
Host: MyExperienceCloudSite.my.site.com
Uvid-Hint: abcd-1234-efgh
Auth-Request-Type: guest

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

## Salesforce Grants a JWT-Based Access Token

After validating the app’s credentials. Salesforce returns a guest JWT-based access token and a state to the browser. The guest access token contains the UVID in the subject (`sub`) claim. Here’s an example snippet of a JWT-based access token. As a reminder, these tokens have three components: a header, payload, and signature. This example shows you the payload with the UVID in the `sub` claim. As you can see, the value is prefixed with `uvid`.

```
{
  "tnk": "example/00XXXXXX",
  "ver": "1.0",
  "kid": "CORE_ATJWT************",
  "tty": "sfdc-core-token",
  "typ": "JWT",
  "alg": "RS256"
}

{
  "scp": "open_id",
  "aud": [
    "https://example.com"
  ],
  "sub": "uvid:abcd-1234-efgh",
  "nbf": "1675197036",
  "iss": "https://MyExperienceCloudSite.my.site.com",
  "exp": "1675198836",
  "iat": "1675197036",
   jti”: xRb**********”
  "client_id": "**********"
}
```

For a full explanation of each claim in a JWT-based access token, see [JWT-Based Access Tokens](https://help.salesforce.com/s/articleView?id=xcloud.jwt_access_tokens.htm&type=5&language=en_US) in Salesforce Help.

## App Creates a Guest Session

Your app processes the access token response and creates a guest session, persisting the UVID value.

## Unknown User Is Now Identified

The unknown end user now has a guest session tied to the UVID value returned in the JWT-based access token. At this point, it’s up to you what you want to do with the UVID. To learn how to pass it into a named user authorization flow, see [Headless Identity APIs: Extending the Headless Guest Flow into a Named User Flow](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_headless_guest_extension.htm&release=264.0.0&type=5 "When you complete a headless guest flow in your off-platform app, you get a guest JWT-based access token with the user’s unique visitor ID (UVID) minted into it. To bring the UVID and all of its associated context into a named user session, you can pass the UVID into a new authorization flow, like a headless login or registration flow.").