Loading
Salesforce now sends email only from verified domains. Read More
Identify Your Users and Manage Access
Table of Contents
Select Filters

          No results
          No results
          Here are some search tips

          Check the spelling of your keywords.
          Use more general search terms.
          Select fewer filters to broaden your search.

          Search all of Salesforce Help
          Headless Identity APIs: Headless Passwordless Login Flow for Public Clients

          Headless Identity APIs: Headless Passwordless Login Flow for Public Clients

          Make it easy for customers and partner users to log in to an off-platform app with the Headless Passwordless Login Flow. With this flow, users log in by entering their email address or phone number and verifying their identity with a one-time password (OTP). You control the front-end experience in your app. On the backend, your app calls Headless Passwordless Login API via an Experience Cloud site to log the user in. These steps show you how the flow works with a public client, like a single-page app, that can’t keep information private.

          Required Editions

          Available in: both Salesforce Classic (not available in all orgs) and Lightning Experience
          Available in: Enterprise, Unlimited, and Developer Editions

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

          Before setting up this flow, complete these steps.

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

          Optionally, for even more flexibility with your user experience, you can use a headless user discovery Apex handler to retrieve users. Develop your handler to look up users based on their email address, phone number, or any other identifier that can be linked to a Salesforce user. For example, prompt users to log in with their travel confirmation number. When the user enters their confirmation number, Salesforce finds the associated username and sends an OTP to the user's email address. For more information about how to develop your Apex handler, see Auth.HeadlessUserDiscoveryHandler in the Apex reference guide.

          For a public client that can’t keep the app’s consumer secret safe, like a mobile app or single-page app, there are some extra security considerations when you build the flow. When you configure your Experience Cloud Login & Registration settings, you must enable at least one of these security options: Require authentication to access this API or Require reCAPTCHA to access this API. For public clients, we recommend that you always enable Require reCAPTCHA to access this API, which requires your app to include a reCAPTCHA token in your initial request to Headless Passwordless Login API. We never recommend that you enable Require authentication to access this API for public clients. This setting requires your request to include an access token issued to an internal integration user, and public clients can’t keep the access token secret.

          To further secure your flow, we always recommend implementing the OAuth 2.0 Proof Key for Code Exchange (PKCE) extension. Traditionally, a private client app uses the consumer secret as a password to securely access Salesforce. But public clients can’t keep the consumer secret safe because they don’t have a private backend. PKCE helps you close this gap with parameters that only your app and Salesforce can verify. These parameters help you ensure that the client that initiates the flow is the same client that completes it.

          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.

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

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

          As mentioned in step 10, this flow requires a callback 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 Salesforce /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 echo endpoint in the code examples for this flow.

          End User Enters Their Email Address or Phone Number for Login

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

          Your App Finds the Username

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

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

          Your App Sends a Request to Headless Passwordless Login API

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

          Include these parameters in the request body.

          Initializing Passwordless Login: Request Body
          Parameter Required? Description
          verificationmethod Yes. The method that you want to use to verify the user’s identity. You can use email or sms.
          username Required if you're not using a headless user discovery handler. The username tied to the email address or phone number that the user submitted.
          recaptcha

          Required if these conditions apply to you.

          • You enabled Require reCAPTCHA to access this API on the Experience Cloud Login & Registration page. We strongly recommend that you always enable this setting for public clients.
          • You're using reCAPTCHA v2 or v3.
          An encrypted token issued by the Google reCAPTCHA API when a user completes a reCAPTCHA challenge.
          recaptchaevent

          Required if these conditions apply to you:

          • You enabled Require reCAPTCHA to access this API on the Experience Cloud Login & Registration settings.
          • You're using reCAPTCHA Enterprise.

          A JSON object containing these subparameters.

          • token—An encrypted token issued by the Google reCAPTCHA API when a user completes a reCAPTCHA challenge.
          • siteKey—The Google reCAPTCHA site key.
          • (Optional)expectedAction—The action that you expect the user to take to initiate reCAPTCHA, such as login. This parameter maps to Google's action parameter.
          • projectId—The project ID from Google.

          For more information, see Google's reCAPTCHA documentation.

          emailtemplate

          Required to specify multiple custom email templates if email template allowlisting is enabled.

          If you didn’t enable email template allowlisting, you can’t include this parameter.

          If you don’t include this parameter, Salesforce uses the default email template configured in your Experience Cloud settings, regardless of whether allowlisting is enabled. If there’s no template configured, Salesforce uses a default OTP email template. The email template language for default templates is controlled by the user’s language settings in Salesforce.

          The custom email template developer name. This parameter can include only an email template from the allowlist.

          To control the language for custom email templates, create templates in the desired language

          login_hint Required if you're using a headless user discovery Apex handler. An identifier that your Apex handler can use to find a user's Salesforce account. For example, collect a user's order number in your app and pass it in the login_hint parameter. We send the login_hint value straight to your Apex handler.

          Here’s an example request to Headless Passwordless Login API. This request is for an implementation that doesn't use a headless user discovery handler.

          POST /services/auth/headless/init/passwordless/login? HTTP 1.1
          Host: MyExperienceCloudSite.my.site.com
          {
           "verificationmethod": "email",
          "username": "janice.edwards@example.com",
          "recaptcha": "***********",
          "emailtemplate": "unfiled$public/SalesNewCustomerEmail"
          }

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

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

          (Optional) Headless User Discovery Handler Finds User

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

          For an example handler, see Auth.HeadlessUserDiscoveryHandler.

          Salesforce Returns a Request Identifier to Your App

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

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

          Salesforce Sends an OTP to the User

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

          Your App Displays a Verification Form

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

          End User Enters OTP

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

          Your App Generates Parameters for PKCE

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

          The PKCE specification defined in RFC 7636 also includes an optional code_challenge_method parameter that you can send in the authorization request. Salesforce ignores any value that you send in this parameter and defaults to SHA256.

          Your App Sends a Request to the Authorization Endpoint

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

          Include these headers in the authorization request.

          Authorization Request: Headers
          Header Required? Description
          Auth-Request-Type Yes. Specifies the type of request you want to make to Salesforce. For headless passwordless login, this value must be set to passwordless-login.
          Auth-Verification-Type Yes. The method used to verify the user’s identity. Salesforce supports two values for the verification method: email and sms.
          Authorization Yes.

          A Basic header identifying the passwordless login request so that Salesforce can link it to the user’s stored information.

          Include the request identifier (identifier) provided by Salesforce and the OTP used to verify the user’s identity. Append these values to each other in the format <identifier:OTP> and Base64-encode the resulting value. The entire header value looks like <Base64-encoded identifier:OTP>.

          Uvid-Hint

          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.

          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.

          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 external client app or connected app to issue JWT-based access tokens and implement the headless guest flow on your app.

          Include these parameters in the request body.

          Authorization Request: Body
          Parameter Required? Description
          response_type Yes. 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_credentials.
          client_id Yes. The consumer key of the external client app or connected app.
          redirect_uri Yes.

          The URL where users are redirected after 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.

          For this flow, you can use the echo endpoint, https://MyExperienceCloudSite.my.site.com/services/oauth2/echo, as your callback endpoint.

          code_challenge Only if you’re using PKCE. PKCE is strongly recommended, especially for public clients.

          Specifies the SHA256 hash value of the code_verifier 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 https://tools.ietf.org/html/rfc4648#section-5

          If a code_challenge is provided in the authorization request and a code_verifier is provided in the token request, Salesforce compares the two values. If the code_challenge is invalid or doesn’t match, the login fails with the invalid_request error code.

          If the code_challenge is provided in the authorization request, but there’s no code_verifier in the token request, the login fails with the invalid_grant error code.

          uvid_hint

          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.

          Instead of passing the UVID in the request body, you can also pass it in a JWT-based token with a UVID via the UVID-Hint header.

          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 external client app or connected app to issue JWT-based access tokens and implement the headless guest flow on your app.

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

          POST /services/oauth2/authorize? HTTP 1.1
          Host: MyExperienceCloudSite.my.site.com
          Auth-Request-Type: passwordless-login
          Auth-Verification-Type: email
          Authorization: Basic <base64-encoded identifier:OTP
          
          response_type=code_credentials&
          client_id=***********&
          redirect_uri=https://www.MyExperienceCloudSite.my.site.com/services/oauth2/echo&
          code_challenge=********
          

          Salesforce Verifies the Request and Returns a 302 Redirect

          When the request hits the authorization endpoint, Salesforce verifies the request identifier and OTP. Salesforce then returns an HTTP 302 redirect to a preconfigured URL containing the authorization code. If the flow is happening in the browser, the 302 redirect is processed in the browser and Salesforce automatically sends the redirect response to the redirect URL, which is the 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 Token Exchange

          Your app receives the code response. To get an access token, the app initiates the code exchange with a headless POST request to the /services/oauth2/token endpoint.

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

          Token Exchange Request: Body Parameters
          Parameter Required? Description
          code Yes. 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.
          client_id Yes. The consumer key of the external client app or connected app.
          redirect_uri Yes.

          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.

          For this flow, you can use the echo endpoint, https://MyExperienceCloudSite.my.site.com/services/oauth2/echo, as your callback endpoint.

          grant_type Yes. The type of validation that the app can provide to prove it’s a safe visitor. For the Authorization Code and Credentials Flow, the value must be authorization_code.
          code_verifier Only if you’re using PKCE.

          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 https://datatracker.ietf.org/doc/html/rfc4648#section-5.

          If there’s a code_verifier value in the token request and a code_challenge value in the authorization request, Salesforce compares the two values. If the code_verifier is invalid or doesn’t match, the login fails with the invalid_grant error code.

          If the code_verifier value is in the token request, but there’s no code_challenge value in the authorization request, the login fails with the invalid_grant error code.

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

          POST services/oauth2/token? HTTP 1.1
          Host: MyExperienceCloudSite.my.site.com
          
          code=********&
          client_id=**********&
          redirect_uri=https://MyExperienceCloudSite.my.site.com/services/oauth2/echo&
          grant_type=authorization_code&
          code_verifier=*******

          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.

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

          The access token response contains these parameters.

          Token Response Parameters
          Parameter Required? Description
          access_token Yes. OAuth token that an external client app or connected app uses to request access to a protected resource on behalf of the client application. Additional permissions in the form of scopes can accompany the access token.
          id Yes. An identity URL that can be used to identify the user and to query for more information about the user. See Identity URLs.
          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.
          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.

          App Creates the User’s Session

          The browser stores the information from the token response and creates the user session. Your app calls the Salesforce User Info endpoint to confirm that the login was successful.

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

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

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

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

          App Makes an Authenticated Call to a Salesforce Endpoint

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

          User Can Access Salesforce Data

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

           
          Loading
          Salesforce Help | Article