AuthVerifyOtp

One-time-code verification page. Renders an InputOTP of N slots and auto-submits when the code is full; routes verification through adapter.verifyOtp({ code, intent }). Optional resend button calls adapter.resendOtp.

Installation

pnpm
pnpm dlx @hex-core/cli add auth-verify-otp

Usage

tsx
import { AuthVerifyOtp } from "@/components/ui/auth-verify-otp"

Sign-in OTP (mock adapter)

Magic-link or email-OTP sign-in flow with auto-submit when full.

tsx
import { AuthVerifyOtp, mockAuthAdapter } from "@hex-core/components";

<AuthVerifyOtp adapter={mockAuthAdapter} intent="sign-in" />

MFA challenge

Second-factor TOTP entry with intent='mfa'.

tsx
<AuthVerifyOtp adapter={authAdapter} intent="mfa" />

API Reference

PropTypeDefaultDescription
adapterrequired
objectAuthAdapter implementation. The block calls adapter.verifyOtp({ code, intent }) when the OTP is full and adapter.resendOtp({ intent }) when the resend button is clicked.
intentrequired
"sign-in" | "verify-email" | "mfa"Reason for the verification. Drives the heading + description copy and is forwarded verbatim to both verifyOtp and resendOtp so consumers can route to the correct backend code.
length
number6Total number of digits in the code. Drives both maxLength on the underlying input-otp library and the number of slots rendered.
resendCooldownSeconds
number30Seconds the resend button stays disabled after each successful resend. Counter ticks down every second while > 0.
className
stringAdditional classes applied to the outer flex wrapper.
onSuccess
functionCalled after a successful verification with the adapter's redirect target: (redirect: string | undefined) => void.

AI Guidance

When to use

Use whenever you need to verify a 6-digit code (or longer) — sign-in via email OTP, post-signup email verification, or TOTP MFA challenge. The intent prop drives both copy and the adapter routing.

When not to use

Don't use for magic-link verification (that lands the user via email click — there's no code to enter). For magic-link wait pages, use auth-verify-email instead.

Common mistakes

  • Submitting the form yourself — the block already auto-submits when the code reaches `length`. Don't render an extra submit button.
  • Hard-coding length=6 when the backend expects a different number — drive `length` from the same constant the email/SMS template uses.
  • Mismatching intent between verifyOtp and resendOtp — the block forwards the same intent to both. If the consumer's adapter routes them differently, that's a bug to fix in the adapter, not the block.
  • Showing the resend button when adapter.resendOtp isn't implemented — the block already hides it; don't re-implement that gate.
  • Setting resendCooldownSeconds too low (< 10s) — invites accidental double-sends and tripping rate-limit responses.

Accessibility

InputOTP is labeled via aria-label='One-time code' so screen readers know what's being entered. Resend button uses the canonical loading prop (sets aria-busy + disabled). Cooldown countdown is reflected in the visible button label. Errors render in an Alert with role='alert'. The OTP value clears on error so users can re-enter without manually deleting digits.

Token budget: 1300

Verified against @hex-core/components@1.9.0