> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Describes how to implement Passwordless authentication using Auth0 APIs.

# Using Passwordless APIs

export const ReleaseStageNotice = ({feature, stage, plans, contact, terms}) => {
  const stageTextMap = {
    "beta": "Beta",
    "ea": "Early Access"
  };
  const stageText = stageTextMap[stage] || "a product release stage";
  const prsLink = "/docs/troubleshoot/product-lifecycle/product-release-stages";
  const linkify = (text, url) => {
    return <a href={url} target="_blank" rel="noreferrer" class="link">{text}</a>;
  };
  const includeDetails = (plans, contact, terms) => {
    const hasDetails = terms || plans || contact;
    if (!hasDetails) return null;
    return <span data-as="p">
            {plans && <>This feature is available for {linkify(`${plans} plans`, "https://auth0.com/pricing")}. </>}
            {contact && "To participate, contact " + contact + ". "}
            {terms && <>By using this feature, you agree to the applicable Free Trial terms in Okta's {linkify("Master Subscription Agreement", "https://www.okta.com/legal")}.</>}
        </span>;
  };
  return <Warning>
            <span data-as="p">
                <strong>The {feature} feature is in {linkify(stageText, prsLink)}.</strong>
            </span>

            {includeDetails(plans, contact, terms)}
        </Warning>;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASKED*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

<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> APIs can be used in two scenarios:

* When implementing <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> and you want to customize the login page using auth0.js to interact with Auth0.
* When you want to embed the login flow in your application.

To learn more about how to implement Passwordless for Universal Login and Embedded login for different scenarios, read [Passwordless Authentication with Universal Login](/docs/authenticate/passwordless/implement-login/universal-login) or [Passwordless Authentication with Embedded Login](/docs/authenticate/passwordless/implement-login/embedded-login).

## Passwordless endpoints

### POST /passwordless/start

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  You must enable the **Passwordless OTP** grant at [Auth0 Dashboard > Applications > Applications](https://manage.auth0.com/#/applications) in your application's settings under **Advanced Settings** > **Grant Types**.
</Callout>

The [POST /passwordless/start](https://auth0.com/docs/api/authentication#get-code-or-link) endpoint can be called to begin the Passwordless authentication process for both Classic Login and Embedded Login.

Depending on the parameters provided to the endpoint, Auth0 begins the user verification process by sending one of the following:

* A single-use code via email or SMS message
* A single-use link via email

The API call must have the following structure:

export const codeExample1 = `POST https://{yourDomain}/passwordless/start
Content-Type: application/json
{
  "client_id": "{yourClientID}",
  "client_secret": "{yourClientSecret}", // For Regular Web Applications
  "connection": "email|sms",
  "email": "{email}", //set for connection=email
  "phone_number": "{phoneNumber}", //set for connection=sms
  "send": "link|code", //if left null defaults to link
  "authParams": { // any authentication parameters that you would like to add
    "scope": "openid",     // used when asking for a magic link
    "state": "{yourState}"  // used when asking for a magic link, or from the custom login page
  }
}`;

<AuthCodeBlock children={codeExample1} language="json" />

If you use a magic link, users will receive a link generated by the Authentication API. Users will select the link and trigger a call to \{`yourAuth0Tenant}.auth0.com/passwordless/verify-redirect`. Auth0 will redirect the user to the application, and the user will be logged in.

If you use a code, your application will need to prompt for that code, and then you should use the `/oauth/token` endpoint, or the `passwordlessLogin` method in the Auth0.js SDK to exchange that code for authentication tokens.

### POST /oauth/token

If you are implementing passwordless for Native Applications or Regular Web Applications, you need to use `/oauth/token` to exchange the OTP code for authentication tokens. You cannot use this endpoint from Single Page Applications.

To achieve this you first need to enable the **Passwordless OTP** grant for your application at [Auth0 Dashboard > Applications > Applications](https://manage.auth0.com/#/applications) in your application's settings under **Advanced Settings** > **Grant Types**.

The user will receive the OTP code and your Native or Web application will prompt the user for it. When the user enters the code, you can complete the authentication flow by calling the `/oauth/token` endpoint with the following parameters:

export const codeExample2 = `POST https://{yourAuth0Domain}/oauth/token
Content-Type: application/json
{
  "grant_type" : "http://auth0.com/oauth/grant-type/passwordless/otp",
  "client_id": "{yourAuth0ClientID}",
  "client_secret": "{yourClientSecret}", // only for web apps, native apps don’t have a client secret
  "username":"<email address>", // or "<phone number>"
  "otp": "CODE",
  "realm": "email", // or "sms" 
  "audience" : "your-api-audience", // in case you need an access token for a specific API
  "scope": "openid profile email" // whatever scopes you need
}`;

<AuthCodeBlock children={codeExample2} language="json" />

If all goes well, Auth0 will return a response similar to the following:

```json lines theme={null}
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token":"eyJz93a...k4laUWw",
"refresh_token":"GEbRxBN...edjnXbL",
"id_token":"eyJ0XAi...4faeEoQ",
"token_type":"Bearer",
"expires_in":86400
}
```

You can then decode the <Tooltip tip="ID Token: Credential meant for the client itself, rather than for accessing a resource." cta="View Glossary" href="/docs/glossary?term=ID+Token">ID Token</Tooltip> to get information about the user, or use the <Tooltip tip="Access Token: Authorization credential, in the form of an opaque string or JWT, used to access an API." cta="View Glossary" href="/docs/glossary?term=Access+Token">Access Token</Tooltip> to call your API as normal.

## Using Auth0.js

When implementing Passwordless Authentication in Single Page Applications or in a customized Universal Login page, you should [use Auth0.js and the included passwordlessLogin method](/docs/libraries/auth0js). The implementation is complex, so we recommend that you use the library instead of calling the APIs directly.

## Rate limiting in passwordless endpoints

Auth0 rate limits and <Tooltip tip="Attack Protection: Features that Auth0 provides to detect and mitigate attacks, including brute-force protection, suspicious IP throttling, breached password detection, bot detection, and adaptive multi-factor authentication." cta="View Glossary" href="/docs/glossary?term=attack+protection">attack protection</Tooltip> features only consider the IP from the machine that is making the API call. When the API call is made from a backend server, you usually want Auth0 to consider the IP from the end user, not the one from the server.

Auth0 supports specifying an `auth0-forwarded-for` header in API calls, but it is only considered when:

* the API call is made for a confidential application.
* the API call includes the <Tooltip tip="Client Secret: Secret used by a client (application) to authenticate with the Authorization Server; it should be known to only the client and the Authorization Server and must be sufficiently random to not be guessable." cta="View Glossary" href="/docs/glossary?term=client+secret">client secret</Tooltip>.
* the **Trust <Tooltip tip="Token Endpoint: Endpoint on the Authorization Server that is used to programmatically request tokens." cta="View Glossary" href="/docs/glossary?term=Token+Endpoint">Token Endpoint</Tooltip> IP Header** toggle is on.

For a complete explanation, read [Avoid Common Issues with Resource Owner Password Flow and Attack Protection](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/avoid-common-issues-with-resource-owner-password-flow-and-attack-protection).

## Customize MFA

<ReleaseStageNotice feature="Customizable MFA with the Resource Owner Password Grant, Embedded, or Refresh Token flows" stage="ea" terms="true" contact="Auth0 Support" />

Customize <Tooltip tip="Multi-factor authentication (MFA): User authentication process that uses a factor in addition to username and password such as a code via SMS." cta="View Glossary" href="/docs/glossary?term=MFA">MFA</Tooltip> with the Passwordless API. When your application calls `/oauth/token` endpoint to request an access token, the <Tooltip tip="Authorization Server: Centralized server that contributes to defining the boundaries of a user’s access. For example, your authorization server can control the data, tasks, and features available to a user." cta="View Glossary" href="/docs/glossary?term=authorization+server">authorization server</Tooltip> returns an `mfa_required` error which provides:

* The `mfa_token` you need to call the MFA API for enrollment and challenges.

* The `mfa_requirements` parameter, which provides the factor `type` your application supports for challenges.

```json lines theme={null}
{
  "error": "mfa_required",
  "error_description": "Multifactor authentication required",
  "mfa_token": "Fe26...Ha",
  "mfa_requirements": {
    "challenge": [
      { "type": "otp" },
      { "type": "push-notification" },
      { "type": "phone" },
      { "type": "recovery-code" }
    ]
  }
}
```

Use the `mfa_token` to call the [`mfa/authenticator`](https://auth0.com/docs/api/authentication/muti-factor-authentication/list-authenticators) endpoint to list all factors the user has enrolled and match the same `type` your application supports. You also need to obtain the matching `authenticator_type` to issue challenges:

```json lines theme={null}
[
  {
    "type": "recovery-code",
    "id": "recovery-code|dev_qpOkGUOxBpw6R16t",
    "authenticator_type": "recovery-code",
    "active": true
  },
  {
    "type": "otp",
    "id": "totp|dev_6NWz8awwC8brh2dN",
    "authenticator_type": "otp",
    "active": true
  }
]
```

Enforce the MFA challenge by calling the [`request/mfa/challenge`](https://auth0.com/docs/api/authentication/muti-factor-authentication/request-mfa-challenge) endpoint.

Further customize your MFA flow with Auth0 Actions. To learn more, read [Actions Triggers: post-challenge - API Object](/docs/customize/actions/explore-triggers/password-reset-triggers/post-challenge-trigger/post-challenge-api-object).
