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/passwordless1. 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.
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | "Sign in" | Form title |
| subtitle | string | - | Description text |
| emailPlaceholder | string | "you@example.com" | Input placeholder |
| submitText | string | "Continue" | Button text |
| showRememberMe | boolean | false | Show remember me checkbox |
| onSuccess | () => void | - | Called on successful login |
| onError | (error: string) => void | - | Called on error |
| logo | ReactNode | - | Custom logo component |
| footer | ReactNode | - | Footer content |
<LoginButton />
Simple button for triggering passwordless auth when you already have the email.
| Prop | Type | Default | Description |
|---|---|---|---|
| string | required | User email address | |
| children | ReactNode | "Sign in with AffirmID" | Button content |
| onSuccess | () => void | - | Called on successful login |
| onError | (error: string) => void | - | Called on error |
| disabled | boolean | false | Disable the button |
<AuthStatus />
Display authentication status and progress.
| Prop | Type | Default | Description |
|---|---|---|---|
| showCancel | boolean | true | Show cancel button during pending |
| messages | Record<AuthState, string> | - | Custom status messages |
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
| apiUrl | string | required | AffirmID API URL |
| apiKey | string | required | Your API key |
| appName | string | - | App name in push notifications |
| timeout | number | 60 | Auth timeout in seconds |
| enableTotpFallback | boolean | true | Show TOTP when push fails |
| enableMagicLinkFallback | boolean | false | Send magic link for new users |
| sessionKey | string | "affirmid_session" | Storage key for session |
| sessionTTL | number | 86400 | Session duration in seconds |
| debug | boolean | false | Enable 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.