@abhiraj_patil/authifyer-sdk
v1.0.16
Published
Drop-in authentication SDK for React — OAuth, Email/Password, OTP verification, session management & pre-built UI components.
Downloads
980
Maintainers
Readme
✨ Features
- 🔐 Email/Password Authentication — Sign up, sign in & OTP email verification out of the box
- 🌐 OAuth Login — One-click Google & GitHub login with automatic token handling
- 🎨 Pre-built UI Components — Beautiful, ready-to-use
<SignIn />,<SignUp />,<UserButton />,<UserProfile />components - 🔄 Automatic Session Management — JWT access tokens with silent refresh, long-lived refresh tokens
- ⚛️ React Hooks —
useAuth(),useUser(),useSession(),useAuthifyer()for full control - 📦 Zero Config — Works with Vite, Next.js, and Create React App
📦 Installation
npm install @abhiraj_patil/authifyer-sdkPeer dependencies (if not already in your project):
npm install react react-dom🚀 Quick Start
1. Get Your Publishable Key
Sign up at the Authifyer Dashboard, create a project, and copy your Publishable Key.
2. Add the Provider
Wrap your app with <AuthifyerProvider>:
// main.tsx or App.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { AuthifyerProvider } from '@abhiraj_patil/authifyer-sdk';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<AuthifyerProvider publishableKey="pk_your_publishable_key_here">
<App />
</AuthifyerProvider>
);3. Add Sign In / Sign Up
import { SignIn, SignUp, useUser } from '@abhiraj_patil/authifyer-sdk';
function App() {
const { user, isSignedIn } = useUser();
if (!isSignedIn) {
return <SignIn />;
// or <SignUp /> for registration
}
return <h1>Welcome, {user?.name}!</h1>;
}That's it! You have a fully working auth flow. 🎉
🔧 Configuration
AuthifyerProvider Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| publishableKey | string | No* | Your project's publishable key |
| backendUrl | string | No | Custom backend URL (for self-hosted deployments) |
| config | ProjectConfig | No | Override project config (useful for testing) |
| children | ReactNode | Yes | Your application tree |
* If not passed as a prop, the SDK will automatically read from environment variables:
- Vite:
VITE_AUTHIFYER_PUBLISHABLE_KEY- Next.js:
NEXT_PUBLIC_AUTHIFYER_PUBLISHABLE_KEY- CRA:
REACT_APP_AUTHIFYER_PUBLISHABLE_KEY
Example with Environment Variable (Vite)
# .env
VITE_AUTHIFYER_PUBLISHABLE_KEY=pk_your_publishable_key_here// No need to pass publishableKey — the SDK reads it from env automatically
<AuthifyerProvider>
<App />
</AuthifyerProvider>Self-Hosted Backend
<AuthifyerProvider
publishableKey="pk_your_key"
backendUrl="https://your-auth-server.example.com"
>
<App />
</AuthifyerProvider>📖 Authentication Methods
1. OAuth Login (Google / GitHub)
The SDK provides one-click OAuth login. When a user clicks the OAuth button, they are redirected to the provider (Google/GitHub), authenticated, and returned to your app with tokens automatically handled.
Using Pre-built Components
The <SignIn /> and <SignUp /> components include OAuth buttons automatically based on your project configuration:
import { SignIn } from '@abhiraj_patil/authifyer-sdk';
function LoginPage() {
return <SignIn />;
}The component will display "Continue with Google" and "Continue with GitHub" buttons if those providers are enabled in your Authifyer dashboard.
Using the Client Directly (Custom UI)
If you want to build your own login UI, use the useAuthifyer() hook:
import { useAuthifyer } from '@abhiraj_patil/authifyer-sdk';
function CustomLogin() {
const client = useAuthifyer();
return (
<div>
<button onClick={() => client.signInWithOAuth('google')}>
Sign in with Google
</button>
<button onClick={() => client.signInWithOAuth('github')}>
Sign in with GitHub
</button>
</div>
);
}How OAuth Works Under the Hood
1. User clicks "Continue with Google"
2. SDK redirects to: /oauth2/authorization/google?publishable_key=<key>&redirect_uri=<origin>
3. User authenticates on Google's consent screen
4. Backend handles the callback, creates a session
5. User is redirected back to your app with ?access_token=...&refresh_token=... in the URL
6. SDK automatically extracts tokens from the URL, stores them, and cleans the URL
7. User is now authenticated ✅2. Email/Password Sign Up
The SDK provides a full registration flow with built-in OTP (One-Time Password) email verification.
Using the Pre-built Component
import { SignUp } from '@abhiraj_patil/authifyer-sdk';
function RegisterPage() {
return <SignUp />;
}How the Sign Up + OTP Verification Flow Works
Step 1: User enters email & password → clicks "Continue"
↓
Step 2: SDK calls POST /authifyer/project/register/email
with { email, password, publicProjectId }
↓
Step 3: Backend creates the user and sends a 6-digit OTP code to the email
Response includes { subjectId, accessToken, refreshToken }
↓
Step 4: SDK automatically switches to the OTP verification screen
Shows "Verify your email — Code sent to [email protected]"
↓
Step 5: User enters the 6-digit code → clicks "Verify Code"
↓
Step 6: SDK calls POST /api/auth/verify-email
with { token: "123456", subjectId: "user-id" }
↓
Step 7: Backend verifies the OTP code
↓
Step 8: On success → user is fully authenticated ✅
On failure → error message, user can retryCustom Sign Up with Manual OTP Handling
import { useAuthifyer } from '@abhiraj_patil/authifyer-sdk';
import { useState } from 'react';
function CustomSignUp() {
const client = useAuthifyer();
const [step, setStep] = useState<'register' | 'verify'>('register');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [subjectId, setSubjectId] = useState('');
const [otpCode, setOtpCode] = useState('');
// Step 1: Register the user
const handleRegister = async () => {
try {
const data = await client.signUpWithEmail(email, password);
if (data?.subjectId) {
setSubjectId(data.subjectId);
setStep('verify'); // Move to OTP verification
}
} catch (err) {
console.error('Registration failed', err);
}
};
// Step 2: Verify the OTP code
const handleVerify = async () => {
try {
await client.verifyEmail(otpCode, subjectId);
// ✅ User is now verified and signed in!
} catch (err) {
console.error('Verification failed', err);
}
};
if (step === 'verify') {
return (
<div>
<h2>Check your email</h2>
<p>We sent a 6-digit code to {email}</p>
<input
value={otpCode}
onChange={(e) => setOtpCode(e.target.value)}
placeholder="Enter 6-digit code"
maxLength={6}
/>
<button onClick={handleVerify}>Verify</button>
</div>
);
}
return (
<div>
<input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
<input value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" type="password" />
<button onClick={handleRegister}>Sign Up</button>
</div>
);
}3. Email/Password Sign In
Using the Pre-built Component
import { SignIn } from '@abhiraj_patil/authifyer-sdk';
function LoginPage() {
return <SignIn />;
}Using the Client Directly
import { useAuthifyer } from '@abhiraj_patil/authifyer-sdk';
function CustomLogin() {
const client = useAuthifyer();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleLogin = async () => {
try {
await client.signInWithEmail(email, password);
// ✅ User is now signed in — session & tokens are managed automatically
} catch (err) {
console.error('Invalid credentials');
}
};
return (
<form onSubmit={(e) => { e.preventDefault(); handleLogin(); }}>
<input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
<input value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" type="password" />
<button type="submit">Sign In</button>
</form>
);
}🎨 Pre-built UI Components
All components come with premium styling out of the box.
<SignIn />
Full sign-in form with OAuth buttons + email/password fields. Adapts automatically to your project's enabled auth methods.
import { SignIn } from '@abhiraj_patil/authifyer-sdk';
<SignIn /><SignUp />
Full registration form with OAuth buttons + email/password fields + OTP email verification flow.
import { SignUp } from '@abhiraj_patil/authifyer-sdk';
<SignUp /><UserButton />
A circular avatar button (shows user initials) that opens a dropdown menu with:
- User info (name & email)
- Manage Account — opens the
<UserProfile />modal - Sign Out
import { UserButton } from '@abhiraj_patil/authifyer-sdk';
function Navbar() {
return (
<nav>
<h1>My App</h1>
<UserButton />
</nav>
);
}<UserProfile />
Full account management modal with:
- Profile overview (name, email, provider, verification status)
- Sign out action
- Delete account (with confirmation prompt)
import { UserProfile } from '@abhiraj_patil/authifyer-sdk';
<UserProfile onClose={() => setShowProfile(false)} />⚛️ React Hooks
useUser()
Returns the current user object and authentication state.
import { useUser } from '@abhiraj_patil/authifyer-sdk';
function Dashboard() {
const { user, isSignedIn, isLoading } = useUser();
if (isLoading) return <p>Loading...</p>;
if (!isSignedIn) return <p>Please sign in</p>;
return (
<div>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
<p>Provider: {user.provider}</p>
<p>Email Verified: {user.emailVerified ? 'Yes' : 'No'}</p>
</div>
);
}useSession()
Returns the current session object with the JWT token.
import { useSession } from '@abhiraj_patil/authifyer-sdk';
function ApiCaller() {
const { session, isSignedIn } = useSession();
const callProtectedApi = async () => {
const res = await fetch('/api/data', {
headers: {
Authorization: `Bearer ${session.token}`,
},
});
// ...
};
}useAuth()
Returns the full auth context including client, user, session, config, and isLoading.
import { useAuth } from '@abhiraj_patil/authifyer-sdk';
function FullControl() {
const { client, user, session, config, isLoading } = useAuth();
// Access everything
}useAuthifyer()
Returns the raw AuthifyerClient instance for direct API calls.
import { useAuthifyer } from '@abhiraj_patil/authifyer-sdk';
function Actions() {
const client = useAuthifyer();
return (
<div>
<button onClick={() => client.signOut()}>Sign Out</button>
<button onClick={() => client.deleteAccount()}>Delete Account</button>
<button onClick={() => client.refreshSession()}>Refresh Session</button>
</div>
);
}🔑 Session & Token Management
The SDK handles session management automatically. Here's how it works:
Token Architecture
| Token | Storage | Lifetime | Purpose |
|-------|---------|----------|---------|
| Access Token (JWT) | localStorage | 5 minutes | Authenticates API requests |
| Refresh Token | localStorage | Long-lived | Obtains new access tokens silently |
Automatic Token Refresh
- The SDK starts a background timer that refreshes the access token every 4.5 minutes (before the 5-minute expiry)
- If the page is reloaded, the SDK restores the session from
localStorage - If the access token has expired but a refresh token exists, the SDK automatically obtains a new access token
- All of this happens silently — no user interaction required
Session Lifecycle
App loads → AuthifyerProvider mounts
↓
SDK checks URL for OAuth redirect tokens
↓ (if found, stores them and cleans URL)
SDK checks localStorage for existing access token
↓ (if valid, restores session)
If no valid access token → tries refresh using refresh token
↓ (if successful, new access token is issued)
If no refresh token → user needs to sign in
After sign in:
Access token → saved to localStorage + Authorization header
Refresh token → saved to localStorage
Auto-refresh timer → started (every 4.5 min)
On sign out:
Tokens → cleared from localStorage
Session → nullified
Timer → stopped🗃️ TypeScript Types
User
interface User {
authifyerId: string; // Unique user ID
name: string; // User's display name
email: string; // User's email address
emailVerified: boolean; // Whether email has been verified
isActive: boolean; // Whether the account is active
provider: string; // Auth provider: 'email' | 'google' | 'github'
}Session
interface Session {
token: string; // The JWT access token
sessionId: string; // Unique session identifier
expireAt: number; // Token expiration timestamp (Unix)
user: User; // The authenticated user
}ProjectConfig
interface ProjectConfig {
projectName?: string; // Your project name
emailPasswordEnabled: boolean; // Is email/password auth enabled
oauthProviders: ('google' | 'github')[]; // Enabled OAuth providers
}🧑💻 Client API Reference
The AuthifyerClient (accessed via useAuthifyer()) exposes these methods:
| Method | Description |
|--------|-------------|
| signInWithEmail(email, password) | Sign in with email & password |
| signUpWithEmail(email, password) | Register a new user (returns subjectId for OTP) |
| verifyEmail(token, subjectId) | Verify email with 6-digit OTP code |
| signInWithOAuth('google' \| 'github') | Redirect to OAuth provider for login |
| signOut() | Sign out and clear all tokens |
| deleteAccount() | Permanently delete the user's account |
| refreshSession() | Manually refresh the access token |
| rotateSession() | Rotate the underlying long-lived session |
📋 Full Example App
// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { AuthifyerProvider } from '@abhiraj_patil/authifyer-sdk';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<AuthifyerProvider publishableKey="pk_your_key_here">
<App />
</AuthifyerProvider>
);// App.tsx
import { useUser, SignIn, SignUp, UserButton } from '@abhiraj_patil/authifyer-sdk';
import { useState } from 'react';
function App() {
const { user, isSignedIn, isLoading } = useUser();
const [isLogin, setIsLogin] = useState(true);
if (isLoading) {
return <div className="loading">Loading...</div>;
}
// Not signed in — show auth forms
if (!isSignedIn) {
return (
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '100vh' }}>
<div>
{isLogin ? <SignIn /> : <SignUp />}
<p style={{ textAlign: 'center', marginTop: '1rem' }}>
{isLogin ? "Don't have an account? " : 'Already have an account? '}
<button onClick={() => setIsLogin(!isLogin)} style={{ color: '#6c63ff', background: 'none', border: 'none', cursor: 'pointer' }}>
{isLogin ? 'Sign Up' : 'Sign In'}
</button>
</p>
</div>
</div>
);
}
// Signed in — show dashboard
return (
<div>
<nav style={{ display: 'flex', justifyContent: 'space-between', padding: '1rem 2rem', borderBottom: '1px solid #eee' }}>
<h1>My App</h1>
<UserButton />
</nav>
<main style={{ padding: '2rem' }}>
<h2>Welcome, {user?.name || user?.email}!</h2>
<p>You are signed in via <strong>{user?.provider}</strong>.</p>
</main>
</div>
);
}
export default App;❓ FAQ
Q: How do I protect routes?
Use the useUser() hook to check authentication state and conditionally render:
const { isSignedIn } = useUser();
if (!isSignedIn) return <Navigate to="/login" />;Q: Can I use this with Next.js?
Yes. Set your key as NEXT_PUBLIC_AUTHIFYER_PUBLISHABLE_KEY in .env.local and wrap your app with <AuthifyerProvider>.
Q: How do I access the JWT token for API calls?
const { session } = useSession();
// Use session.token in your Authorization headerQ: What happens when the access token expires?
The SDK automatically refreshes it every 4.5 minutes. Your users will never experience token expiry interruptions.
📄 License
ISC
