> ## Documentation Index
> Fetch the complete documentation index at: https://docs-staging-quickstart-revamp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Guide to implement ACUL for the Passwordless Login flow

# Build SMS & Email Passwordless Login

<Card title="Before you start">
  You need:

  * An Auth0 development tenant with Universal Login configured.
  * A custom-domain-configured application.
  * A development app or a sample app (like the [React sample app](/docs/quickstart/spa/react)) running on your localhost
  * A database connection that uses a passwordless connection.
</Card>

By the end of this flow, you'll have a customized <Tooltip tip="Passwordless: Form of authentication that does not rely on a password as the first factor." cta="View Glossary" href="/docs/glossary?term=Passwordless">Passwordless</Tooltip> login screen with the option for email or SMS.

To learn more, read the [Getting Started guide](/docs/customize/login-pages/advanced-customizations/getting-started) and visit the [SDK reference guide](/docs/customize/login-pages/advanced-customizations/getting-started/sdk-quickstart).

## Setup

In your <Tooltip tip="Auth0 Dashboard: Auth0's main product to configure your services." cta="View Glossary" href="/docs/glossary?term=Auth0+Dashboard">Auth0 Dashboard</Tooltip>, set up [Universal Login](/docs/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/universal-experience), [Identifier First Authentication](/docs/authenticate/login/auth0-universal-login/identifier-first), and a [Database Connection](/docs/get-started/applications/set-up-database-connections) that uses passwords.

Run a single-page application to build custom login screens. To understand the context for Advanced Customizations interfaces, clone our boilerplate app: `git clone https://github.com/auth0/auth0-acul-react-boilerplate`

Install the [ACUL SDK](/docs/customize/login-pages/advanced-customizations/getting-started/sdk-quickstart). After cloning the react boilerplate, change the directory to the `auth0-acul-react-boilerplate` folder and install the SDK.

```bash lines
# Clone the ACUL sample application into the root folder of your project

git clone https://github.com/auth0-samples/auth0-acul-samples.git

# Change directory to install the ACUL sample application 

cd auth0-acul-samples && npm i
```

## Option 1: Build the Passwordless Login screen for email

<Frame>
  <img src="https://mintcdn.com/docs-staging-quickstart-revamp/R8rXfTj95YBIEuC2/images/cdy7uua7fh8z/4DKgjU2dGw0mpLJKGfGhp0/470b29266da87f9bfc3e7eef55069620/Login_Passwordless_Email_Code.png?fit=max&auto=format&n=R8rXfTj95YBIEuC2&q=85&s=011d4760e9ba7a51d62833e362021b79" alt="Login Passwordless Email Code" width="480" height="576" data-path="images/cdy7uua7fh8z/4DKgjU2dGw0mpLJKGfGhp0/470b29266da87f9bfc3e7eef55069620/Login_Passwordless_Email_Code.png" />
</Frame>

Below is a full sample of the Screen. This example uses [Shadcn components](https://ui.shadcn.com/docs/installation/vite#edit-tsconfigjson-file).

<Accordion title="Passwordless Email">
  ```jsx lines expandable
  import { ChangeEvent } from "react";
  import { LoginPasswordlessEmailCode as ScreenProvider } from "@auth0/auth0-acul-js";

  // UI Components
  import { Label } from "@/components/ui/label";
  import { Button } from "@/components/ui/button";
  import { Text } from "@/components/ui/text";
  import { Link } from "@/components/ui/link";
  import { Input } from "@/components/ui/input";
  import { REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp"
  import {
    InputOTP,
    InputOTPGroup,
    InputOTPSlot,
  } from "@/components/ui/input-otp"
  import {
    CardHeader,
    CardTitle,
    CardDescription,
    CardContent,
  } from "@/components/ui/card";

  export default function LoginPasswordlessEmailCode() {
    // Initialize the SDK for this screen
    const screenProvider = new ScreenProvider();

    // Handle the submit action
    const formSubmitHandler = (event: ChangeEvent<HTMLFormElement>) => {
      event.preventDefault();

      // grab the value from the form
      const OtpInput = event.target.querySelector(
        "input#otp_code"
      ) as HTMLInputElement;
      const identifierInput = event.target.querySelector(
        "input#identifier"
      ) as HTMLInputElement;

      // Call the SDK
      screenProvider.submitCode({
        username: identifierInput?.value,
        code: OtpInput?.value
      });
    };

    // Render the form
    return (
      <form noValidate onSubmit={formSubmitHandler}>
        <CardHeader>
          <CardTitle className="mb-2 text-3xl font-medium text-center">
            {screenProvider.screen.texts?.title ?? "Verify yourself"}
          </CardTitle>
          <CardDescription className="mb-8 text-center">
            {screenProvider.screen.texts?.description ??
              "Enter the code sent to the email below"}
          </CardDescription>
        </CardHeader>
        <CardContent>
          <Text className="mb-4 text-large">
            <span className="inline-block">
              Continue as
              <span className="inline-block ml-1 font-bold">
                {screenProvider.screen.data?.username}.
              </span>
            </span>
            <Link
              href={screenProvider.screen.links.editIdentifierLink ?? "#"}
              className="ml-2"
            >
              {screenProvider.screen.texts?.editText ?? "Edit Email"}
            </Link>
          </Text>
          <Input
            type="hidden"
            name="identifier"
            id="identifier"
            value={screenProvider.screen.data?.username}
          />
          <Label htmlFor="otp_code">
            {screenProvider.screen.texts?.placeholder ?? "Enter the OTP Code"}
          </Label>
          <div className="flex items-center w-full space-y-2">
            <InputOTP
              maxLength={6}
              pattern={REGEXP_ONLY_DIGITS_AND_CHARS}
              id="otp_code"
              name="otp_code"
            >
              <InputOTPGroup>
                <InputOTPSlot index={0} />
                <InputOTPSlot index={1} />
                <InputOTPSlot index={2} />
                <InputOTPSlot index={3} />
                <InputOTPSlot index={4} />
                <InputOTPSlot index={5} />
              </InputOTPGroup>
            </InputOTP>
            <Button type="submit" className="ml-2">
              {screenProvider.screen.texts?.buttonText ?? "Verify"}
            </Button>
          </div>
          <Text>
            {screenProvider.screen.texts?.resendText ?? "Didn't get the OTP?"}
            <Link className="ml-1" href="#" onClick={screenProvider.resendCode}>
              {screenProvider.screen.texts?.resendActionText ?? "Send again."}
            </Link>
          </Text>
        </CardContent>
      </form>
    );
  }
  ```
</Accordion>

### Import and initialize the SDK

In the `auth0-acul-react-boilerplate/src` folder, create a folder called `screens` and a file called `Login.tsx` Import the SDK and in the React component initialize the SDK for the screen.

```jsx lines
import { LoginPasswordlessEmailCode as ScreenProvider } from "@auth0/auth0-acul-js";

export default function LoginPasswordlessEmailCode() {
  // Initialize the SDK for this screen
  const screenProvider = new ScreenProvider();
  ...
 }
```

### Use the SDK to access properties and methods on the screen

Using the SDK you can access the properties and methods of the screen. The [Auth0 ACUL JS SDK](/docs/customize/login-pages/advanced-customizations/getting-started/sdk-quickstart) provides properties and methods to access the data.

```jsx lines expandable
<form noValidate onSubmit={formSubmitHandler}>
      ...
      <CardContent>
        <Text className="mb-4 text-large">
          <span className="inline-block">
            Continue as
            <span className="inline-block ml-1 font-bold">
              {screenProvider.screen.data?.username}.
            </span>
          </span>
          <Link
            href={screenProvider.screen.links.editIdentifierLink ?? "#"}
            className="ml-2"
          >
            {screenProvider.screen.texts?.editText ?? "Edit Email"}
          </Link>
        </Text>
        <Input
          type="hidden"
          name="identifier"
          id="identifier"
          value={screenProvider.screen.data?.username}
        />
        <Label htmlFor="otp_code">
          {screenProvider.screen.texts?.placeholder ?? "Enter the OTP Code"}
        </Label>
        <div className="flex items-center w-full space-y-2">
          <InputOTP
            maxLength={6}
            pattern={REGEXP_ONLY_DIGITS_AND_CHARS}
            id="otp_code"
            name="otp_code"
          >
            <InputOTPGroup>
              <InputOTPSlot index={0} />
              <InputOTPSlot index={1} />
              <InputOTPSlot index={2} />
              <InputOTPSlot index={3} />
              <InputOTPSlot index={4} />
              <InputOTPSlot index={5} />
            </InputOTPGroup>
          </InputOTP>
          <Button type="submit" className="ml-2">
            {screenProvider.screen.texts?.buttonText ?? "Verify"}
          </Button>
        </div>
      ...
      </CardContent>
    </form>
  );
}
```

### Call the submit action

Using the SDK, submit the data captured in the screen to the server. The server process this data and will route the user to the next step in the flow. If there are errors, this screen is reloaded, allowing you to display them to the user. Errors are accessed from the SDK.

```javascript lines
const formSubmitHandler = (event: ChangeEvent<HTMLFormElement>) => {
    event.preventDefault();

    // grab the value from the form
    const OtpInput = event.target.querySelector(
      "input#otp_code"
    ) as HTMLInputElement;
    const identifierInput = event.target.querySelector(
      "input#identifier"
    ) as HTMLInputElement;

    // Call the SDK
    screenProvider.submitCode({
      username: identifierInput?.value,
      code: OtpInput?.value
    });
```

## Option 2: Build the Passwordless Login screen for SMS

<Frame>
  <img src="https://mintcdn.com/docs-staging-quickstart-revamp/jp6vZz7DhptSlPIu/images/cdy7uua7fh8z/7qSqOazAiuhuPciX0J7s9i/95c56f70a27b333e25963f7a71fb16a3/Login_Passwordless_SMS_OTP.png?fit=max&auto=format&n=jp6vZz7DhptSlPIu&q=85&s=89041683f1259dbbf4f7d99e6b6706b0" alt="Login Passwordless SMS OTP" width="960" height="1152" data-path="images/cdy7uua7fh8z/7qSqOazAiuhuPciX0J7s9i/95c56f70a27b333e25963f7a71fb16a3/Login_Passwordless_SMS_OTP.png" />
</Frame>

Below is a full sample of the Screen.

<Accordion title="Passwordless for SMS">
  ```jsx lines expandable
  import { ChangeEvent } from "react";
  import { LoginPasswordlessSmsOtp as ScreenProvider } from "@auth0/auth0-acul-js";

  // UI Components
  import { Label } from "@/components/ui/label";
  import { Button } from "@/components/ui/button";
  import { Text } from "@/components/ui/text";
  import { Link } from "@/components/ui/link";
  import { Input } from "@/components/ui/input";
  import { REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp"
  import {
    InputOTP,
    InputOTPGroup,
    InputOTPSlot,
  } from "@/components/ui/input-otp"
  import {
    CardHeader,
    CardTitle,
    CardDescription,
    CardContent,
  } from "@/components/ui/card";

  export default function LoginPasswordlessSmsOtp() {
    // Initialize the SDK for this screen
    const screenProvider = new ScreenProvider();

    // Handle the submit action
    const formSubmitHandler = (event: ChangeEvent<HTMLFormElement>) => {
      event.preventDefault();

      // grab the value from the form
      const OtpInput = event.target.querySelector(
        "input#otp_code"
      ) as HTMLInputElement;
      const identifierInput = event.target.querySelector(
        "input#identifier"
      ) as HTMLInputElement;

      // Call the SDK
      screenProvider.submitOTP({
        username: identifierInput?.value,
        code: OtpInput?.value
      });
    };

    // Render the form
    return (
      <form noValidate onSubmit={formSubmitHandler}>
        <CardHeader>
          <CardTitle className="mb-2 text-3xl font-medium text-center">
            {screenProvider.screen.texts?.title ?? "Verify yourself"}
          </CardTitle>
          <CardDescription className="mb-8 text-center">
            {screenProvider.screen.texts?.description ??
              "Enter the code sent to the phone below"}
          </CardDescription>
        </CardHeader>
        <CardContent>
          <Text className="mb-4 text-large">
            <span className="inline-block">
              Continue as
              <span className="inline-block ml-1 font-bold">
                {screenProvider.screen.data?.username}.
              </span>
            </span>
            <Link
              href={screenProvider.screen.links?.edit_identifier ?? "#"}
              className="ml-2"
            >
              {screenProvider.screen.texts?.editText ?? "Edit Phone"}
            </Link>
          </Text>
          <Input
            type="hidden"
            name="identifier"
            id="identifier"
            value={screenProvider.screen.data?.username}
          />
          <Label htmlFor="otp_code">
            {screenProvider.screen.texts?.placeholder ?? "Enter the OTP Code"}
          </Label>
          <div className="flex items-center w-full space-y-2">
            <InputOTP
              maxLength={6}
              pattern={REGEXP_ONLY_DIGITS_AND_CHARS}
              id="otp_code"
              name="otp_code"
            >
              <InputOTPGroup>
                <InputOTPSlot index={0} />
                <InputOTPSlot index={1} />
                <InputOTPSlot index={2} />
                <InputOTPSlot index={3} />
                <InputOTPSlot index={4} />
                <InputOTPSlot index={5} />
              </InputOTPGroup>
            </InputOTP>
            <Button type="submit" className="ml-2">
              {screenProvider.screen.texts?.buttonText ?? "Verify"}
            </Button>
          </div>
          <Text>
            {screenProvider.screen.texts?.resendText ?? "Didn't get the OTP?"}
            <Link className="ml-1" href="#" onClick={screenProvider.resendOTP}>
              {screenProvider.screen.texts?.resendActionText ?? "Send again."}
            </Link>
          </Text>
        </CardContent>
      </form>
    );
  }
  ```
</Accordion>

### Import and initialize the SDK

In the `auth0-acul-react-boilerplate/src` folder, create a folder called `screens` and a file called `Login.tsx`. Import the SDK and in the React component initialize the SDK for the screen.

```jsx lines
import { LoginPasswordlessSmsOtp as ScreenProvider } from "@auth0/auth0-acul-js";

export default function LoginPasswordlessSmsOtp() {
  // Initialize the SDK for this screen
  const screenProvider = new ScreenProvider();
  ...
 }
```

### Use the SDK to access properties and methods on the screen

Using the SDK you can access the properties and methods of the screen. The [Auth0 ACUL JS SDK](/docs/customize/login-pages/advanced-customizations/getting-started/sdk-quickstart) provides properties and methods to access the data.

```jsx lines expandable
<form noValidate onSubmit={formSubmitHandler}>
       ...
      <CardContent>
        <Text className="mb-4 text-large">
          <span className="inline-block">
            Continue as
            <span className="inline-block ml-1 font-bold">
              {screenProvider.screen.data?.username}.
            </span>
          </span>
          <Link
            href={screenProvider.screen.links?.edit_identifier ?? "#"}
            className="ml-2"
          >
            {screenProvider.screen.texts?.editText ?? "Edit Phone"}
          </Link>
        </Text>
        <Input
          type="hidden"
          name="identifier"
          id="identifier"
          value={screenProvider.screen.data?.username}
        />
        <Label htmlFor="otp_code">
          {screenProvider.screen.texts?.placeholder ?? "Enter the OTP Code"}
        </Label>
        <div className="flex items-center w-full space-y-2">
          <InputOTP
            maxLength={6}
            pattern={REGEXP_ONLY_DIGITS_AND_CHARS}
            id="otp_code"
            name="otp_code"
          >
            <InputOTPGroup>
              <InputOTPSlot index={0} />
              <InputOTPSlot index={1} />
              <InputOTPSlot index={2} />
              <InputOTPSlot index={3} />
              <InputOTPSlot index={4} />
              <InputOTPSlot index={5} />
            </InputOTPGroup>
          </InputOTP>
          <Button type="submit" className="ml-2">
            {screenProvider.screen.texts?.buttonText ?? "Verify"}
          </Button>
        </div>
       ...
      </CardContent>
    </form>
  );
}
```

### Call the submit action

Using the SDK, submit the data captured in the screen to the server. The server process this data and will route the user to the next step in the flow. If there are errors, this screen is reloaded, allowing you to display them to the user. Errors are accessed from the SDK.

```javascript lines
const formSubmitHandler = (event: ChangeEvent<HTMLFormElement>) => {
    event.preventDefault();

    // grab the value from the form
    const OtpInput = event.target.querySelector(
      "input#otp_code"
    ) as HTMLInputElement;
    const identifierInput = event.target.querySelector(
      "input#identifier"
    ) as HTMLInputElement;

    // Call the SDK
    screenProvider.submitCode({
      username: identifierInput?.value,
      code: OtpInput?.value
    });
```

## Step 3: Configure ACUL to use local assets

Use Auth0 CLI, Terraform, or the <Tooltip tip="Management API: A product to allow customers to perform administrative tasks." cta="View Glossary" href="/docs/glossary?term=Management+API">Management API</Tooltip> to enable ACUL. For details about what can be configured, read [Configure ACUL Screens](/docs/customize/login-pages/advanced-customizations/getting-started/configure-acul-screens).

<Tabs>
  <Tab title="Auth0 CLI (Recommended)">
    In the root directory of your project, create a `settings` folder and include in it a `{SCREENNAME}.json` file.

    ```javascript lines expandable
    //settings.json
    {
      "rendering_mode": "advanced",
      "context_configuration": [
        "screen.texts"
      ],
      "head_tags": [
        {
          "attributes": {
            "async": true,
            "defer": true,
            "integrity": [
              "ASSET_SHA"
            ],
            "src": "http://127.0.0.1:8080/index.js"
          },
          "tag": "script"
        },
        {
          "attributes": {
            "href": "http://127.0.0.1:8080/index.css",
            "rel": "stylesheet"
          },
          "tag": "link"
        }
      ]
    }
    ```

     Enable ACUL with Auth0 CLI:

    ```bash wrap lines
    auth0 ul customize --rendering-mode advanced --prompt {SCREENNAME} --screen {SCREENNAME} --settings-file ./settings/{SCREENNAME}.json
    ```
  </Tab>

  <Tab title="Auth0 Terraform">
    In the root directory of your project, create a `login-id.json` file:

    ```javascript lines expandable
    //login-id.json
    {
      "rendering_mode": "advanced",
      "context_configuration": [
        "screen.texts"
      ],
      "head_tags": [
        {
          "attributes": {
            "async": true,
            "defer": true,
            "integrity": [
              "ASSET_SHA"
            ],
            "src": "http://127.0.0.1:8080/index.js"
          },
          "tag": "script"
        },
        {
          "attributes": {
            "href": "http://127.0.0.1:8080/index.css",
            "rel": "stylesheet"
          },
          "tag": "link"
        }
      ]
    }
    ```

     Enable ACUL with Auth0 Terraform

    ```yaml lines
    prompts:
      identifier_first: true
      universal_login_experience: classic
            mfa-login-options:
              pageTitle: 'Log in to ${clientName}'
              authenticatorNamesSMS: 'SMS'
      screenRenderers:
        - login-id:
            login-id: ./prompts/screenRenderSettings/login-id.json
    ```
  </Tab>

  <Tab title="Auth0 Management API">
    You can use Auth0 Management API to enable ACUL

    ```bash lines expandable
    curl --location --request PATCH 'https://{YOUR-CUSTOM-DOMAIN}/api/v2/prompts/{YOUR-PROMPT}/screen/{YOUR-SCREEN}/rendering' \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <API TOKEN>' \
    --data '{
        "rendering_mode": "advanced",
            "context_configuration": [
            "branding.settings",
            "organization.branding",
            "screen.texts",
            "tenant.name",
            "tenant.friendly_name",
            "tenant.enabled_locales",
            "untrusted_data.submitted_form_data",
            "untrusted_data.authorization_params.ui_locales",
            "untrusted_data.authorization_params.login_hint",
            "untrusted_data.authorization_params.screen_hint"
        ],
        "head_tags": [
          {
            "tag": "script",
            "attributes": {
              "src": "http://127.0.0.1:8080/index.js",
              "defer": true
            }
          },
          {
            "tag": "link",
            "attributes": {
              "rel": "stylesheet",
              "href": "http://127.0.0.1:8080/index.css"
            }
          },
          {
            "tag": "meta",
            "attributes": {
              "name": "viewport",
              "content": "width=device-width, initial-scale=1"
            }
          }
        ]
    }'
    ```
  </Tab>
</Tabs>

### Test your configuration on a local server

ACUL requires assets to be hosted on a public URL. Run a local server and test your assets before deploying them.

```javascript lines
// Creates the local assets 

npm run build 
cd dist 

// Serves the assets from localhost

npx serve -p 8080 --cors
```

## Step 4: Deploy the assets and update your tenant configuration

Advanced Customization for <Tooltip tip="Universal Login: Your application redirects to Universal Login, hosted on Auth0's Authorization Server, to verify a user's identity." cta="View Glossary" href="/docs/glossary?term=Universal+Login">Universal Login</Tooltip> works with all modern Javascript bundlers. like Vite and Webpack. For more information, read [Deploy and Host Advanced Customizations](/docs/customize/login-pages/advanced-customizations/getting-started/deploy-and-host-advanced-customizations).

For more information about deploying ACUL to your tenant, read [Configure ACUL Screens.](/docs/customize/login-pages/advanced-customizations/getting-started/configure-acul-screens)

## Related content

For more information about screens that can be customized, read [Advanced Customization JS SDK Reference](/docs/customize/login-pages/advanced-customizations/reference).
