SMS Authentication
SMS auth is currently in closed alpha. If you’d like early access please reach out to [email protected].
Authenticate users with their phone number by sending verification codes via SMS.
How It Works
SMS authentication is a two-step process:
- Send the verification code: the user enters their phone number and requests a verification code.
- Submit the verification code: the user enters the 6-digit code they receive via SMS to complete authentication.
The SDK will handle phone number validation, code generation, and delivery automatically.
We support all major countries across Europe, Asia, North and South America.
Pricing varies by country and requires specific area codes to be enabled for your account.
Prerequisites
- Early access to SMS auth configured on your account: Request early access!
- A configured app with smart wallets and a gas sponsorship policy.
- SDK version ≥v4.53.0
Implementation
React
React Native
Javascript
SMS auth is not yet supported with pre-built UI components. Please follow this guide to set up custom UI and configure authentication with hooks.
Step 1: Send the SMS verification code
Ensure you pass the phone number including the country code in the format +<country code><phone number>
(i.e. `+15553219876).
import { function useAuthenticate(mutationArgs?: UseAuthenticateMutationArgs): UseAuthenticateResultHook that provides functions and state for authenticating a user using a signer. It includes methods for both synchronous and asynchronous mutations. Useful if building your own UI components and want to control the authentication flow. For authenticate vs authenticateAsync, use authenticate when you want the hook the handle state changes for you, authenticateAsync when you need to wait for the result to finish processing.
This can be complex for magic link or OTP flows: OPT calls authenticate twice, but this should be handled by the signer.
useAuthenticate } from "@account-kit/react"
const { const authenticate: UseMutateFunction<User, Error, AuthParams, unknown>authenticate } = function useAuthenticate(mutationArgs?: UseAuthenticateMutationArgs): UseAuthenticateResultHook that provides functions and state for authenticating a user using a signer. It includes methods for both synchronous and asynchronous mutations. Useful if building your own UI components and want to control the authentication flow. For authenticate vs authenticateAsync, use authenticate when you want the hook the handle state changes for you, authenticateAsync when you need to wait for the result to finish processing.
This can be complex for magic link or OTP flows: OPT calls authenticate twice, but this should be handled by the signer.
useAuthenticate()
const const handleSendCode: (phone: string) => voidhandleSendCode = (phone: stringphone: string) => {
const authenticate: (variables: AuthParams, options?: MutateOptions<User, Error, AuthParams, unknown> | undefined) => voidauthenticate(
{ type: "sms"type: "sms", phone: stringphone: "+123456789" },
{
MutateOptions<User, Error, AuthParams, unknown>.onSuccess?: ((data: User, variables: AuthParams, onMutateResult: unknown, context: MutationFunctionContext) => void) | undefinedonSuccess: () => {
// onSuccess only fires once the entire flow is done (SMS OTP + optional MFA).
// It still runs even if the final step completes in another tab/window.
},
MutateOptions<User, Error, AuthParams, unknown>.onError?: ((error: Error, variables: AuthParams, onMutateResult: unknown, context: MutationFunctionContext) => void) | undefinedonError: (error: Errorerror) => {
// Handle error
},
},
);
};
Step 2: Show OTP input on status change
Use the useSignerStatus
hook to show the otp input once the code is sent:
import React from "react";
import { const useSignerStatus: (override?: AlchemyAccountContextProps) => UseSignerStatusResultHook to get the signer status, optionally using an override configuration, useful if you’re building your own login.
useSignerStatus } from "@account-kit/react";
import { enum AlchemySignerStatusAlchemySignerStatus } from "@account-kit/signer";
const const TrackStatus: () => JSX.ElementTrackStatus = () => {
const { const status: AlchemySignerStatusstatus } = function useSignerStatus(override?: AlchemyAccountContextProps): UseSignerStatusResultHook to get the signer status, optionally using an override configuration, useful if you’re building your own login.
useSignerStatus();
return (
<>
{const status: AlchemySignerStatusstatus === enum AlchemySignerStatusAlchemySignerStatus.function (enum member) AlchemySignerStatus.AWAITING_SMS_AUTH = "AWAITING_SMS_AUTH"AWAITING_SMS_AUTH && (
<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>Prompt the user to enter the OTP code received via SMS</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>
)}
</>
);
};
Step 3: Verify the OTP code
import { function useAuthenticate(mutationArgs?: UseAuthenticateMutationArgs): UseAuthenticateResultHook that provides functions and state for authenticating a user using a signer. It includes methods for both synchronous and asynchronous mutations. Useful if building your own UI components and want to control the authentication flow. For authenticate vs authenticateAsync, use authenticate when you want the hook the handle state changes for you, authenticateAsync when you need to wait for the result to finish processing.
This can be complex for magic link or OTP flows: OPT calls authenticate twice, but this should be handled by the signer.
useAuthenticate } from "@account-kit/react";
const { const authenticate: UseMutateFunction<User, Error, AuthParams, unknown>authenticate } = function useAuthenticate(mutationArgs?: UseAuthenticateMutationArgs): UseAuthenticateResultHook that provides functions and state for authenticating a user using a signer. It includes methods for both synchronous and asynchronous mutations. Useful if building your own UI components and want to control the authentication flow. For authenticate vs authenticateAsync, use authenticate when you want the hook the handle state changes for you, authenticateAsync when you need to wait for the result to finish processing.
This can be complex for magic link or OTP flows: OPT calls authenticate twice, but this should be handled by the signer.
useAuthenticate();
// When the user submits the OTP code
const const handleVerifyCode: (otpCode: string) => voidhandleVerifyCode = (otpCode: stringotpCode: string) => {
const authenticate: (variables: AuthParams, options?: MutateOptions<User, Error, AuthParams, unknown> | undefined) => voidauthenticate(
{
type: "otp"type: "otp",
otpCode: stringotpCode,
},
{
MutateOptions<User, Error, AuthParams, unknown>.onSuccess?: ((data: User, variables: AuthParams, onMutateResult: unknown, context: MutationFunctionContext) => void) | undefinedonSuccess: () => {
// onSuccess only fires once the entire flow is done (SMS OTP).
},
MutateOptions<User, Error, AuthParams, unknown>.onError?: ((error: Error, variables: AuthParams, onMutateResult: unknown, context: MutationFunctionContext) => void) | undefinedonError: (error: Errorerror) => {
// Handle invalid code error
},
},
);
};
Step 4: Check authentication status
Use the useSignerStatus
hook we set up before to wait until the user is authenticated:
import { const useSignerStatus: (override?: AlchemyAccountContextProps) => UseSignerStatusResultHook to get the signer status, optionally using an override configuration, useful if you’re building your own login.
useSignerStatus } from "@account-kit/react";
// Inside your component
const { const isConnected: booleanisConnected } = function useSignerStatus(override?: AlchemyAccountContextProps): UseSignerStatusResultHook to get the signer status, optionally using an override configuration, useful if you’re building your own login.
useSignerStatus();
// You can use isConnected to conditionally render UI
Next Steps
- Send transactions