Skip to content

Email Login

Varity Team Core Contributors Updated March 2026

Add passwordless email login to your app. Users receive a magic link with no passwords to remember and no password resets to handle.

  1. User enters their email address
  2. They receive a magic link via email
  3. Clicking the link logs them in
  4. Session is maintained across page refreshes

No password storage, no forgotten password flows, no security vulnerabilities from weak passwords.

  1. Set up your auth provider

    app/layout.tsx
    import { PrivyStack } from '@varity-labs/ui-kit';
    export default function RootLayout({ children }) {
    return (
    <html>
    <body>
    <PrivyStack loginMethods={['email']}>
    {children}
    </PrivyStack>
    </body>
    </html>
    );
    }
  2. Add the login button

    components/LoginButton.tsx
    import { PrivyLoginButton } from '@varity-labs/ui-kit';
    export function LoginButton() {
    return (
    <PrivyLoginButton>
    Sign in with Email
    </PrivyLoginButton>
    );
    }

Build your own login button using the usePrivy hook:

components/CustomEmailLogin.tsx
import { usePrivy, useLogin } from '@varity-labs/ui-kit';
export function CustomEmailLogin() {
const { ready, authenticated } = usePrivy();
const { login } = useLogin();
if (!ready) {
return <button disabled>Loading...</button>;
}
if (authenticated) {
return <span>Already logged in</span>;
}
return (
<button
onClick={login}
className="bg-blue-600 text-white px-4 py-2 rounded-lg"
>
Continue with Email
</button>
);
}

After login, access the user’s email from the user object:

components/UserProfile.tsx
import { usePrivy } from '@varity-labs/ui-kit';
export function UserProfile() {
const { user } = usePrivy();
if (!user) return null;
return (
<div>
<p>Email: {user.email?.address}</p>
<p>Verified: {user.email?.verified ? 'Yes' : 'No'}</p>
</div>
);
}

The typical user experience:

1. User clicks "Sign in with Email"
2. Modal appears asking for email address
3. User enters email and clicks "Continue"
4. Magic link email is sent (arrives in ~5 seconds)
5. User clicks link in email
6. User is logged in and redirected back to your app

Execute custom logic when a user successfully logs in:

components/LoginWithCallback.tsx
import { PrivyLoginButton } from '@varity-labs/ui-kit';
export function LoginWithCallback() {
const handleSuccess = (user) => {
// Track login analytics
analytics.track('user_logged_in', {
email: user.email?.address,
method: 'email',
});
// Redirect to dashboard
router.push('/dashboard');
};
const handleError = (error) => {
console.error('Login failed:', error);
toast.error('Login failed. Please try again.');
};
return (
<PrivyLoginButton
onSuccess={handleSuccess}
onError={handleError}
>
Sign in with Email
</PrivyLoginButton>
);
}

Only show content to logged-in users:

pages/dashboard.tsx
import { PrivyProtectedRoute, usePrivy } from '@varity-labs/ui-kit';
function DashboardContent() {
const { user } = usePrivy();
return (
<div>
<h1>Welcome, {user?.email?.address}!</h1>
<p>This is your private dashboard.</p>
</div>
);
}
export default function Dashboard() {
return (
<PrivyProtectedRoute>
<DashboardContent />
</PrivyProtectedRoute>
);
}

To only allow email login (no social providers):

app/layout.tsx
<PrivyStack loginMethods={['email']}>
{children}
</PrivyStack>

This simplifies the login modal to only show an email input field.