Clerk logo

Clerk Docs

Ctrl + K
Go to clerkstage.dev

Email / SMS OTP

Learn how to send one-time codes (OTP) to authenticate users.

Overview

Clerk supports passwordless authentication, which lets users sign in and sign up without having to remember a password. During sign-in, users will be asked to enter their identifier (email address or phone number) to receive a one-time code and complete the authentication process.

Arguably, passwordless authentication provides greater security and a better user experience than traditional passwords. However, it is not without its downsides, and often still boils down to the email providers "knowledge based factor" instead of yours.

There are multiple ways to set up passwordless authentication in Clerk such as Clerk Components, or by creating a custom flow using Clerk's SDKs.

The rest of this guide will explain how to set up passwordless authentication using any of the above methods. Before you start, you will need to configure your instance to allow passwordless sign-ins.

Looking for magic links? Check out our Magic links authentication guide.

Looking for 2FA? Check out our Multi-factor authentication guide.

Before you start

Configuration

Passwordless authentication can be configured through the Clerk Dashboard. Go to your instance, then User & Authentication > Email, Phone, Username > Authentication factors. Simply choose one of the available passwordless authentication strategies that send one-time codes; Email verification code or SMS verification code.

sms verification

Don't forget that you also need to make sure you've configured your application instance to request the user's contact information. Users can receive one-time codes via either an email address or a phone number.

Make sure you toggle one of Email address, Phone number on in the Contact information section. Once you've enabled one of the two contact information options, ensure it can be used for identification. Click the cog on the top-right, and verify that the Used for identification toggle is on.

phone number toggle modal

Don't forget to click on the Apply Changes button at the bottom of the page once you're done configuring your instance.

That's all you need to do to enable passwordless authentication with One-time codes for your instance.

Custom flow

In case one of the above integration methods doesn't cover your needs, you can make use of lower-level commands and create a completely custom passwordless authentication flow.

You still need to configure your instance in order to enable passwordless authentication, as described at the top of this guide.

Sign up using a custom flow

The passwordless sign-up flow is a process that requires users to provide their authentication identifier (email address or phone number) and a one-time code that is sent to them. The important thing to note here is that a user's email address or phone number needs to be verified before the registration is completed.

A successful sign-up consists of the following steps:

  1. Initiate the sign-up process, by collecting the user's identifier (email address or phone number).
  2. Prepare the identifier verification.
  3. Attempt to complete the identifier verification.

Let's see the above in action. If you want to learn more about sign-ups, check out our documentation on Clerk's sign-up flow.

1
import { useSignUp } from "@clerk/clerk-react";
2
3
function SignUpPage() {
4
const { signUp,setActive } = useSignUp();
5
6
async function onClick(e) {
7
e.preventDefault();
8
// Kick off the sign-up process, passing the user's
9
// phone number.
10
await signUp.create({
11
phoneNumber: "+11111111111",
12
});
13
14
// Prepare phone number verification. An SMS message
15
// will be sent to the user with a one-time
16
// verification code.
17
await signUp.preparePhoneNumberVerification();
18
19
// Attempt to verify the user's phone number by
20
// providing the one-time code they received.
21
await signUp.attemptPhoneNumberVerification({
22
code: "123456",
23
});
24
25
await setActive({sessionId: signUp.createdSessionId});
26
}
27
28
return (
29
<button onClick={onClick}>
30
Sign up without password
31
</button>
32
);
33
}
1
const { client } = window.Clerk;
2
3
// Kick off the sign-up process, passing the user's
4
// phone number.
5
const signUp = await client.signUp.create({
6
phoneNumber: "+11111111111",
7
});
8
9
// Prepare phone number verification. An SMS will
10
// be sent to the user with a one-time verification
11
// code.
12
await signUp.preparePhoneNumberVerification();
13
14
// Attempt to verify the user's phone number by providing
15
// the one-time code they received.
16
await signUp.attemptPhoneNumberVerification({
17
code: "123456",
18
});

You can also verify your users via their email address. There's two additional helper methods, prepareEmailAddressVerification and attemptEmailAddressVerification that work the same way as their phone number counterparts do. You can find more available methods in our ClerkJS API documentation for the SignUp object.

Sign in using a custom flow

The passwordless sign-in flow is a process that requires users to provide their authentication identifier (email address or phone number) and subsequently a one-time code that is sent to them. We call this one-time code the first factor of authentication.

So, in essence, when you want to authenticate users in your application, you need to

  1. Initiate the sign-in process, by collecting the user's authentication identifier.
  2. Prepare the first factor verification.
  3. Attempt to complete the first factor verification.

Let's see the above in action. If you want to learn more about sign-ins, check out our documentation on Clerk's sign-in flow.

1
import { useSignIn } from "@clerk/clerk-react";
2
3
function SignInPage() {
4
const { signIn,setActive } = useSignIn();
5
6
async function onClick(e) {
7
e.preventDefault();
8
// Kick off the sign-in process, passing the user's
9
// authentication identifier. In this case it's their
10
// phone number.
11
const { supportedFirstFactors } = await signIn.create({
12
identifier: "+11111111111",
13
});
14
15
// Find the phoneNumberId from all the available first factors for the current sign in
16
const firstPhoneFactor = supportedFirstFactors.find(factor => {
17
return factor.strategy === 'phone_code'
18
});
19
20
const { phoneNumberId } = firstPhoneFactor;
21
22
// Prepare first factor verification, specifying
23
// the phone code strategy.
24
await signIn.prepareFirstFactor({
25
strategy: "phone_code",
26
phoneNumberId,
27
});
28
29
// Attempt to verify the user providing the
30
// one-time code they received.
31
await signIn.attemptFirstFactor({
32
strategy: "phone_code",
33
code: "123456",
34
});
35
36
await setActive({sessionId: signIn.createdSessionId});
37
}
38
39
return (
40
<button onClick={onClick}>
41
Sign in without password
42
</button>
43
);
44
}
1
const { client } = window.Clerk;
2
// Kick off the sign-in process, passing the user's
3
// authentication identifier. In this case it's their
4
// phone number.
5
const { supportedFirstFactors } = await client.signIn.create({
6
identifier: "+11111111111",
7
});
8
9
// Find the phoneNumberId from all the available first factors for the current sign in
10
const firstPhoneFactor = supportedFirstFactors.find(factor => {
11
return factor.strategy === 'phone_code'
12
});
13
14
const { phoneNumberId } = firstPhoneFactor;
15
16
// Prepare first factor verification, specifying
17
// the phone code strategy.
18
await signIn.prepareFirstFactor({
19
strategy: "phone_code",
20
phoneNumberId,
21
});
22
23
// Attempt to verify the user providing the
24
// one-time code they received.
25
await signIn.attemptFirstFactor({
26
strategy: "phone_code",
27
code: "123456",
28
});

You can also achieve passwordless sign-ins with an email address. Simply pass the value email_code as the first factor strategy. Just make sure you've collected the user's email address first. You can find all available methods on the SignIn object documentation.

Was this helpful?

Clerk © 2023