Number Match Approval

Approve your sign-in

Open the Beste app on your phone and tap the number you see below to continue.

42
Waiting for approval…

Didn't start this? Cancel sign-in

This request expires in 60 seconds.

About this block

Number Match ApprovalPRO

Full-height push-approval screen that shows a large number to match in your authenticator app, with a live waiting indicator and a cancel option. Perfect for number-matching two-factor authentication.

Auth35: Number Match Approval

A full-height, centered push-approval screen that stacks an optional circular icon, a heading, a description, a large bordered match number, a pulsing "waiting" indicator, a cancel prompt link, and a footer note, all inside a max-w-md column for number-matching two-factor authentication.

Upgrade to Pro

Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.

Upgrade Now

Installation

Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.

Radix flavor

bash
npx shadcn add "https://ui.beste.co/r/auth35?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

bash
npx shadcn add "https://ui.beste.co/r-base/auth35?email=YOUR_EMAIL&license_key=YOUR_KEY"

This installs the block to components/beste/block/auth35.tsx.

Quick start

The installed file exports auth35Demo alongside the block: the exact props behind the preview above. Spread it to get a working approval screen in one line.

tsx
import { Auth35, auth35Demo } from "@/components/beste/block/auth35";

export default function Page() {
  return <Auth35 {...auth35Demo} />;
}

Then replace the demo with your own props. Written out, a trimmed setup looks like this:

tsx
import { Smartphone } from "lucide-react";
import { Auth35 } from "@/components/beste/block/auth35";

export default function Page() {
  return (
    <Auth35
      icon={<Smartphone className="size-6" />}
      heading="Approve your sign-in"
      description="Open the app on your phone and tap the number below to continue."
      matchNumber="42"
      labels={{
        waiting: "Waiting for approval…",
        footer: "This request expires in 60 seconds.",
      }}
      cancelPrompt={{
        text: "Didn't start this?",
        linkLabel: "Cancel sign-in",
        href: "/logout",
      }}
    />
  );
}

Props

PropTypeDefaultDescription
iconReact.ReactNode–Node placed inside the top circular badge; the badge is omitted entirely when absent
headingstring–Main <h1> title
descriptionstring–Supporting paragraph under the heading
matchNumberstring–Value rendered large in the bordered match box
labels{ waiting?: string; footer?: string }{}Text for the waiting indicator and the footer line
cancelPrompt{ text: string; linkLabel: string; href: string }–Prompt text plus a linked cancel action
classNamestring–Extra classes for the outer <section>
ts
type Labels = {
  waiting?: string;
  footer?: string;
};

type CancelPrompt = {
  text: string;
  linkLabel: string;
  href: string;
};

Behavior notes

  • The block is purely presentational: it holds no useState, fires no callbacks, and never polls, so the actual approval/rejection flow (checking whether the user tapped the number) must be wired up by the integrator around it.
  • Every visible region is conditionally rendered on its own prop being truthy, so passing only heading yields just the title with no icon badge, match box, waiting row, or footer.
  • The cancel action is a next/link Link pointing at cancelPrompt.href; it is a plain navigation, not a handler, so cancellation happens by routing to whatever URL you supply.
  • matchNumber is typed as string and rendered with tabular-nums, so multi-digit or leading-zero values (for example "07") display exactly as passed rather than being coerced.
  • The "waiting" row includes a decorative animate-ping dot that loops indefinitely on its own; it reflects nothing about real request state and keeps animating even after approval.
  • Text values are inserted as plain children (no dangerouslySetInnerHTML), so inline markup in heading or description is shown as literal text, not parsed as HTML.
  • The root <section> forces min-h-screen, so the screen always fills the viewport height and vertically centers its content regardless of how little is rendered.

More Auth blocks

View all Auth
PRO

auth46

Confirm It's You

PRO

auth39

Enable Two-Factor

PRO

auth12

Email Confirmed Success

Get Pro access