New Feature

Passwordless Authentication

Add secure, push-based login to your website in minutes. No passwords, no friction.

Quick Start

Install the package
npm install @affirmid/passwordless

1. Create API Routes

Create app/api/auth/passwordless/[action]/route.ts:

typescript
import { createPasswordlessRouteHandler } from '@affirmid/passwordless/next';

const handler = createPasswordlessRouteHandler({
  apiUrl: process.env.AFFIRMID_API_URL!,
  apiKey: process.env.AFFIRMID_API_KEY!,
  appName: 'My App',
});

export { handler as POST, handler as GET };

2. Add Middleware (Optional)

Protect routes automatically with middleware.ts:

typescript
import { createPasswordlessMiddleware } from '@affirmid/passwordless/next';

export default createPasswordlessMiddleware({
  protectedPaths: ['/dashboard', '/account'],
  loginPath: '/login',
});

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};

3. Create Login Page

tsx
'use client';

import { PasswordlessProvider, LoginForm } from '@affirmid/passwordless/next';
import '@affirmid/passwordless/styles.css';

export default function LoginPage() {
  return (
    <PasswordlessProvider
      apiUrl={process.env.NEXT_PUBLIC_AFFIRMID_API_URL!}
      apiKey={process.env.NEXT_PUBLIC_AFFIRMID_API_KEY!}
    >
      <div className="min-h-screen flex items-center justify-center">
        <LoginForm
          title="Welcome back"
          onSuccess={() => window.location.href = '/dashboard'}
        />
      </div>
    </PasswordlessProvider>
  );
}

How It Works

1

Enter Email

User enters their email address

2

Push Sent

Notification sent to their phone

3

Approve

User taps approve in the app

4

Logged In

Session created, user redirected

Components

<LoginForm />

Full-featured login form with email input, status display, and TOTP fallback.

PropTypeDefaultDescription
titlestring"Sign in"Form title
subtitlestring-Description text
emailPlaceholderstring"you@example.com"Input placeholder
submitTextstring"Continue"Button text
showRememberMebooleanfalseShow remember me checkbox
onSuccess() => void-Called on successful login
onError(error: string) => void-Called on error
logoReactNode-Custom logo component
footerReactNode-Footer content

<LoginButton />

Simple button for triggering passwordless auth when you already have the email.

PropTypeDefaultDescription
emailstringrequiredUser email address
childrenReactNode"Sign in with AffirmID"Button content
onSuccess() => void-Called on successful login
onError(error: string) => void-Called on error
disabledbooleanfalseDisable the button

<AuthStatus />

Display authentication status and progress.

PropTypeDefaultDescription
showCancelbooleantrueShow cancel button during pending
messagesRecord<AuthState, string>-Custom status messages

Configuration

OptionTypeDefaultDescription
apiUrlstringrequiredAffirmID API URL
apiKeystringrequiredYour API key
appNamestring-App name in push notifications
timeoutnumber60Auth timeout in seconds
enableTotpFallbackbooleantrueShow TOTP when push fails
enableMagicLinkFallbackbooleanfalseSend magic link for new users
sessionKeystring"affirmid_session"Storage key for session
sessionTTLnumber86400Session duration in seconds
debugbooleanfalseEnable console logging

Styling

Import the default styles or customize with CSS variables:

css
:root {
  --affirmid-primary: #6366f1;
  --affirmid-primary-hover: #4f46e5;
  --affirmid-success: #10b981;
  --affirmid-error: #ef4444;
  --affirmid-text: #1f2937;
  --affirmid-bg: #ffffff;
  --affirmid-border: #e5e7eb;
  --affirmid-radius: 8px;
}

Or use Tailwind CSS classes directly on components:

tsx
<LoginForm className="bg-white shadow-xl rounded-2xl p-8" />

Ready to go passwordless?

Get your API key and start integrating in minutes.