React integration for Passkeyme Authentication SDK - Simple single dependency installation
npm install @passkeyme/react-authReact integration for Passkeyme Authentication SDK. Build secure authentication into your React apps with hooks and components.
- ๐ช React Hooks: usePasskeyme(), useAuth(), useAuthState()
- ๐งฉ Pre-built Components: Login buttons, user profiles, protected routes
- ๐ Automatic State Management: Context-based state with automatic updates
- ๐จ Customizable UI: Styled components with full customization options
- ๐ก๏ธ Type Safety: Full TypeScript support
- โก Zero Config: Works out of the box with sensible defaults
``bash`
npm install @passkeyme/auth @passkeyme/react-auth
Peer Dependencies:
- React >= 16.8.0
- React DOM >= 16.8.0
Wrap your app with the PasskeymeProvider:
`tsx
import { PasskeymeProvider } from "@passkeyme/react-auth";
function App() {
return (
appId: "your-passkeyme-app-id",
redirectUri: "http://localhost/auth/callback",
debug: process.env.NODE_ENV === "development", // Enable debug logging in development
}}
>
);
}
`
`tsx
import { usePasskeyme, PasskeymeCallbackHandler } from "@passkeyme/react-auth";
import { BrowserRouter, Routes, Route } from "react-router-dom";
function App() {
return (
{/ Built-in callback handler - handles all authentication flows /}
);
}
function Dashboard() {
const { user, loginWithOAuth, logout, loading } = usePasskeyme();
if (loading) {
return
if (!user) {
return (
);
}
return (
$3
`tsx
import {
PasskeymeOAuthButton,
PasskeymeButton,
PasskeymeUserProfile,
PasskeymeProtectedRoute,
} from "@passkeyme/react-auth";function LoginPage() {
return (
);
}function Dashboard() {
return (
}>
Protected Content
);
}
`๐ API Reference
$3
The main provider component that manages authentication state.
`tsx
config={{
appId: "your-app-id",
redirectUri: "http://localhost:3000/callback",
debug: true, // Enable debug logging for development
}}
loadingComponent={Loading...}
errorComponent={error => Error: {error}}
onAuthChange={user => console.log("User changed:", user)}
onError={error => console.error("Auth error:", error)}
>
`> Note: Set
debug: false or omit the debug flag in production to prevent debug messages from appearing in the browser console.$3
Main hook providing full authentication functionality.
`tsx
const {
user, // Current user or null
loading, // Loading state
error, // Error message or null
isAuthenticated, // Boolean auth status // Login methods
login, // Generic login with options
loginWithOAuth, // OAuth login (redirects)
loginWithPasskey, // Passkey authentication
loginWithPassword, // Username/password login
handleCallback, // Handle OAuth callback
// Other methods
logout, // Logout user
getAccessToken, // Get current token
refreshToken, // Refresh token
auth, // Direct access to auth instance
} = usePasskeyme();
`$3
Get only the authentication state (no methods).
`tsx
const { user, loading, error, isAuthenticated } = useAuthState();
`$3
Get only the authentication methods (no state).
`tsx
const {
login,
loginWithOAuth,
loginWithPasskey,
loginWithPassword,
logout,
getAccessToken,
refreshToken,
} = useAuth();
`๐งฉ Components
$3
โญ NEW: Built-in component that automatically handles all authentication callbacks.
The
PasskeymeCallbackHandler eliminates the need to write custom callback logic. Just add it to your routing:`tsx
import { PasskeymeCallbackHandler } from '@passkeyme/react-auth';// Basic usage - handles everything automatically
} />
// With custom redirects and components
path="/callback"
element={
successRedirect="/dashboard"
errorRedirect="/login"
loadingComponent={CustomSpinner}
errorComponent={CustomError}
/>
}
/>
`Features:
- โ
Handles both OAuth (
?code=...) and hosted auth (?token=...) flows
- โ
Built-in loading and error states with customizable components
- โ
Automatic token validation and user state management
- โ
NEW: Automatic passkey registration prompting (enabled by default)
- โ
Configurable success/error redirects
- โ
Custom event callbacks for advanced use cases
- โ
URL cleanup after processingSee CALLBACK_HANDLER.md for complete documentation.
$3
OAuth login button with built-in styling.
`tsx
provider="google" // 'google' | 'github' | 'facebook'
variant="default" // 'default' | 'outlined' | 'text'
size="medium" // 'small' | 'medium' | 'large'
redirectUri="/custom/callback"
disabled={false}
loading={false}
onClick={() => console.log("Clicked")}
className="custom-class"
>
Custom Button Text
`$3
Passkey authentication button.
`tsx
username="user@example.com" // Optional username hint
variant="default"
size="medium"
onSuccess={user => console.log("Success:", user)}
onError={error => console.log("Error:", error)}
>
Sign in with Passkey
`$3
User profile display with avatar and logout.
`tsx
showAvatar={true}
showName={true}
showEmail={true}
showLogout={true}
avatarSize={40}
logoutText="Sign Out"
onLogout={() => console.log("Logged out")}
className="profile-container"
/>
`$3
Protect content for authenticated users.
`tsx
fallback={ }
redirectTo="/login"
requiredRoles={["admin", "user"]}
hasAccess={user => user.emailVerified}
>
`$3
Higher-order component for protecting components.
`tsx
const ProtectedComponent = withAuth(MyComponent, {
fallback: Please login,
requiredRoles: ["admin"],
});
`๐ Programmatic Authentication
$3
โญ NEW: Enhanced programmatic authentication with mode support for hosted vs inline OAuth flows.
`tsx
// Simple hosted flow (default - redirects to hosted auth pages)
const { triggerPasskeymeAuth } = usePasskeyme();
triggerPasskeymeAuth();// Custom success/error handling
triggerPasskeymeAuth({
username: "user@example.com",
onSuccess: (user, method) => console.log(
Authenticated via ${method}, user),
onError: error => console.error("Auth failed:", error),
});// Inline mode - developer controls OAuth UI
triggerPasskeymeAuth({
mode: "inline",
onOAuthRequired: providers => {
// Show your custom OAuth UI
setShowOAuthModal(true);
setAvailableProviders(providers);
},
onSuccess: (user, method) => {
setShowOAuthModal(false);
console.log(
Success via ${method}, user);
},
});// Passkey-only (no fallback)
triggerPasskeymeAuth({
forcePasskeyOnly: true,
onError: error => alert("Passkey authentication failed"),
});
`Mode Options:
-
hosted (default): Try passkey โ redirect to hosted auth pages
- inline: Try passkey โ callback with OAuth providers for custom UIThis gives you maximum flexibility - use hosted mode for simple setup, or inline mode for full UI control.
$3
`tsx
function CustomAuthFlow() {
const { triggerPasskeymeAuth } = usePasskeyme();
const [showOAuth, setShowOAuth] = useState(false);
const [providers, setProviders] = useState([]); const handleLogin = () => {
triggerPasskeymeAuth({
mode: "inline",
onOAuthRequired: availableProviders => {
setProviders(availableProviders);
setShowOAuth(true);
},
onSuccess: (user, method) => {
setShowOAuth(false);
console.log(
Authenticated via ${method});
},
});
}; return (
{showOAuth && (
Choose OAuth Provider
{providers.map(provider => (
Login with {provider}
))}
)}
);
}
`๐จ Customization
$3
All components accept
className and can be styled with CSS:`css
.login-button {
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border-radius: 20px;
}.user-profile {
border: 2px solid #f0f0f0;
border-radius: 8px;
padding: 16px;
}
`$3
Create your own components using the hooks:
`tsx
function CustomLoginForm() {
const { loginWithPassword, loading, error } = usePasskeyme();
const [email, setEmail] = useState("");
const [password, setPassword] = useState(""); const handleSubmit = async e => {
e.preventDefault();
try {
await loginWithPassword(email, password);
} catch (err) {
// Error handled by hook
}
};
return (
);
}
`๐ Integration Examples
$3
`tsx
// app/layout.tsx
import { PasskeymeProvider } from "@passkeyme/react-auth";export default function RootLayout({ children }) {
return (
config={{ appId: process.env.NEXT_PUBLIC_PASSKEYME_APP_ID }}
>
{children}
);
}// app/dashboard/page.tsx
import { ProtectedRoute, UserProfile } from "@passkeyme/react-auth";
export default function Dashboard() {
return (
Dashboard
);
}
`$3
`tsx
import { BrowserRouter, Route, Routes, Navigate } from "react-router-dom";
import { usePasskeyme } from "@passkeyme/react-auth";function AppRouter() {
const { isAuthenticated, loading } = usePasskeyme();
if (loading) return
Loading...; return (
} />
path="/dashboard"
element={isAuthenticated ? : }
/>
);
}
`๐ TypeScript Support
This package provides comprehensive TypeScript definitions for type-safe authentication.
$3
`typescript
import type {
User,
AuthConfig,
AuthState,
PasskeyCredential,
OAuthProvider,
UsePasskeymeReturn,
} from "@passkeyme/react-auth";// User object structure
interface User {
id: string;
email: string;
name?: string;
avatar?: string;
metadata?: Record;
}
// Authentication configuration
interface AuthConfig {
appId: string;
baseUrl?: string;
redirectUri: string;
debug?: boolean;
}
// Hook return type
interface UsePasskeymeReturn {
// State
user: User | null;
isAuthenticated: boolean;
loading: boolean;
error: Error | null;
// Actions
loginWithOAuth: (provider: OAuthProvider) => Promise;
loginWithPasskey: () => Promise;
loginWithCredentials: (email: string, password: string) => Promise;
register: (email: string, password: string, name?: string) => Promise;
logout: () => Promise;
// Utility
refreshToken: () => Promise;
getAuthHeader: () => string | null;
}
`$3
`typescript
import { PasskeymeProvider } from "@passkeyme/react-auth";
import type { AuthConfig } from "@passkeyme/react-auth";const authConfig: AuthConfig = {
appId: process.env.REACT_APP_PASSKEYME_APP_ID!,
redirectUri:
${window.location.origin}/auth/callback,
debug: process.env.NODE_ENV === "development",
};function App() {
return (
);
}
`$3
`typescript
import { usePasskeyme } from "@passkeyme/react-auth";
import type { User } from "@passkeyme/react-auth";// Custom hook for user profile management
function useUserProfile() {
const { user, updateProfile } = usePasskeyme();
const updateUserProfile = async (updates: Partial) => {
if (!user) throw new Error("User not authenticated");
return updateProfile({
...user,
...updates,
});
};
return {
user,
updateUserProfile,
hasProfile: Boolean(user?.name),
isEmailVerified: user?.emailVerified ?? false,
};
}
`๐ Integration Guides
$3
`typescript
// pages/_app.tsx
import { AppProps } from "next/app";
import { PasskeymeProvider } from "@passkeyme/react-auth";export default function App({ Component, pageProps }: AppProps) {
return (
config={{
appId: process.env.NEXT_PUBLIC_PASSKEYME_APP_ID!,
redirectUri:
${process.env.NEXT_PUBLIC_BASE_URL}/auth/callback,
}}
>
);
}// pages/auth/callback.tsx
import { PasskeymeCallbackHandler } from "@passkeyme/react-auth";
export default function AuthCallback() {
return ;
}
// Custom hook for Next.js router integration
import { useRouter } from "next/router";
import { usePasskeyme } from "@passkeyme/react-auth";
import { useEffect } from "react";
export function useAuthRedirect() {
const { isAuthenticated, loading } = usePasskeyme();
const router = useRouter();
useEffect(() => {
if (!loading && !isAuthenticated) {
router.push("/login");
}
}, [isAuthenticated, loading, router]);
return { isAuthenticated, loading };
}
`$3
`typescript
// main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { PasskeymeProvider } from "@passkeyme/react-auth";
import App from "./App";ReactDOM.createRoot(document.getElementById("root")!).render(
config={{
appId: import.meta.env.VITE_PASSKEYME_APP_ID,
redirectUri:
${window.location.origin}/auth/callback,
debug: import.meta.env.DEV,
}}
>
);// vite-env.d.ts - Environment variables
interface ImportMetaEnv {
readonly VITE_PASSKEYME_APP_ID: string;
// Add other env variables as needed
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
`$3
`typescript
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import { PasskeymeCallbackHandler, usePasskeyme } from "@passkeyme/react-auth";// Protected Route Component
interface ProtectedRouteProps {
children: React.ReactNode;
fallback?: React.ReactNode;
}
function ProtectedRoute({ children, fallback }: ProtectedRouteProps) {
const { isAuthenticated, loading } = usePasskeyme();
if (loading) return
Loading...; if (!isAuthenticated) {
return fallback ? <>{fallback}> : ;
}
return <>{children}>;
}
function AppRouter() {
return (
} />
} />
path="/dashboard"
element={
}
/>
} />
);
}
`$3
`typescript
import { usePasskeyme } from "@passkeyme/react-auth";
import { useEffect, useState } from "react";function LoginWithErrorHandling() {
const { loginWithOAuth, error, loading } = usePasskeyme();
const [loginError, setLoginError] = useState(null);
const handleLogin = async (provider: "google" | "github") => {
try {
setLoginError(null);
await loginWithOAuth(provider);
} catch (err) {
setLoginError(err instanceof Error ? err.message : "Login failed");
}
};
// Handle authentication errors
useEffect(() => {
if (error) {
console.error("Authentication error:", error);
setLoginError(error.message);
}
}, [error]);
return (
{loginError && (
{loginError}
)}
);
}
`๐งช Testing Integration
$3
`typescript
// test-utils.tsx
import React from "react";
import { render, RenderOptions } from "@testing-library/react";
import { PasskeymeProvider } from "@passkeyme/react-auth";
import type { AuthConfig } from "@passkeyme/react-auth";const mockAuthConfig: AuthConfig = {
appId: "test-app-id",
redirectUri: "http://localhost:3000/callback",
debug: false,
};
interface CustomRenderOptions extends Omit {
authConfig?: Partial;
}
export function renderWithAuth(
ui: React.ReactElement,
{ authConfig = {}, ...options }: CustomRenderOptions = {}
) {
const config = { ...mockAuthConfig, ...authConfig };
function Wrapper({ children }: { children: React.ReactNode }) {
return {children} ;
}
return render(ui, { wrapper: Wrapper, ...options });
}
// Component test example
import { screen, fireEvent, waitFor } from "@testing-library/react";
import { usePasskeyme } from "@passkeyme/react-auth";
function TestComponent() {
const { user, loginWithOAuth, loading } = usePasskeyme();
return (
{user ? (
{user.email}
) : (
)}
);
}test("handles login flow", async () => {
renderWithAuth( );
const loginButton = screen.getByText("Login");
fireEvent.click(loginButton);
expect(screen.getByText("Loading...")).toBeInTheDocument();
await waitFor(() => {
expect(screen.getByTestId("user-info")).toBeInTheDocument();
});
});
`๐ Package Integration
$3
This package builds on top of
@passkeyme/react-core for shared patterns:`typescript
// Access core patterns directly
import {
usePasskeymeContext,
PasskeymeProvider as CoreProvider,
} from "@passkeyme/react-core";// Or use the enhanced React-specific provider
import { PasskeymeProvider } from "@passkeyme/react-auth";
// Custom hook using core patterns
function useCustomAuth() {
const { state, dispatch } = usePasskeymeContext();
const customLogin = async () => {
dispatch({ type: "SET_LOADING", payload: true });
try {
// Custom authentication logic
const user = await customAuthFlow();
dispatch({ type: "SET_USER", payload: user });
} catch (error) {
dispatch({ type: "SET_ERROR", payload: error });
} finally {
dispatch({ type: "SET_LOADING", payload: false });
}
};
return { ...state, customLogin };
}
`$3
`typescript
import { PasskeymeAuth } from "@passkeyme/auth";
import { usePasskeyme } from "@passkeyme/react-auth";// Access the core auth instance
function AdvancedAuthComponent() {
const { auth } = usePasskeyme();
const handleAdvancedFlow = async () => {
// Direct access to core SDK methods
const tokens = await auth.getTokens();
const userInfo = await auth.getUserInfo();
// Custom API calls with auth headers
const response = await fetch("/api/protected", {
headers: {
Authorization:
Bearer ${tokens.accessToken},
},
});
}; return ;
}
``| Feature | @passkeyme/react-auth | Firebase Auth | Auth0 React |
| --------------------- | ------------------------- | ----------------- | ------------------ |
| Setup Lines | โ
5 lines | โ 20+ lines | โ 15+ lines |
| Built-in Passkeys | โ
Native support | โ Manual setup | โ Manual setup |
| Type Safety | โ
Full TypeScript | โ ๏ธ Partial | โ
Full TypeScript |
| Bundle Size | โ
Small | โ Large | โ Large |
| Self-Hosting | โ
Yes | โ No | โ No |
| Vendor Lock-in | โ
None | โ High | โ High |
MIT - see LICENSE file for details.
- Documentation: https://passkeyme.com/docs/react
- Issues: https://github.com/passkeyme/passkeyme/issues
- Discord: https://discord.gg/passkeyme