fauthy-next-sdk
v0.3.4
Published
Next.js auth client for Fauthy
Readme
Fauthy Next.js SDK
A comprehensive authentication SDK for Next.js applications using Fauthy.
Installation
npm install fauthy-next-sdkUsage
Basic Setup
import { FauthyClient } from 'fauthy-next-sdk';
const client = new FauthyClient({
secret: process.env.FAUTHY_SECRET!,
login_url: '/auth/login',
login_redirect_url: '/dashboard',
logout_redirect_url: '/',
});React Components
import { FauthyProvider, useUser } from 'fauthy-next-sdk';
import { getSession, ensureValidSession } from 'fauthy-next-sdk/utils/api-routes';
import { me } from 'fauthy-next-sdk';
// In your app layout (server component)
export default async function RootLayout({ children }) {
const secret = process.env.FAUTHY_SECRET!;
const session = await getSession(secret);
let user = null;
if (session) {
try {
const validSession = await ensureValidSession(secret, session);
const userResponse = await me(validSession);
if (userResponse.status.code === 200) {
user = userResponse.data;
}
} catch (error) {
// Handle error
}
}
return (
<FauthyProvider user={user}>
{children}
</FauthyProvider>
);
}
// In client components
function YourComponent() {
const user = useUser();
if (!user) return <div>Please log in</div>;
return <div>Welcome, {user.first_name}!</div>;
}API Functions
import {
signInMagicLink,
authorize,
logout,
me,
updateMe
} from 'fauthy-next-sdk';
// Server actions
export async function handleLogin(formData: FormData) {
return await signInMagicLink({}, formData);
}Utility Functions
JWT and Claims Utilities
import {
decodeJWTClaims,
formatAccessClaims,
getClaimsFromSession
} from 'fauthy-next-sdk';
// Decode JWT token claims
const claims = await decodeJWTClaims(accessToken);
// Format raw claims into structured AccessClaims
const accessClaims = formatAccessClaims(claims);
// Get claims from server-side session
const sessionClaims = await getClaimsFromSession(session);Role-Based Access Control
import {
hasRole,
hasAnyRole,
hasAllRoles
} from 'fauthy-next-sdk';
// Check for specific role
if (hasRole(claims, 'admin')) {
// User has admin role
}
// Check for any of multiple roles
if (hasAnyRole(claims, ['admin', 'moderator'])) {
// User has admin OR moderator role
}
// Check for all specified roles
if (hasAllRoles(claims, ['admin', 'superuser'])) {
// User has both admin AND superuser roles
}Permission-Based Access Control
import {
hasPermission,
hasAnyPermission,
hasAllPermissions,
getClaimsPermissions
} from 'fauthy-next-sdk';
// Check for specific permission
if (hasPermission(claims, 'user:read')) {
// User can read users
}
// Check for any of multiple permissions
if (hasAnyPermission(claims, ['user:read', 'user:write'])) {
// User can read OR write users
}
// Check for all specified permissions
if (hasAllPermissions(claims, ['user:read', 'user:write'])) {
// User can read AND write users
}
// Get all user permissions
const permissions = getClaimsPermissions(claims);React Components with Role/Permission Checks
import { useClaims } from 'fauthy-next-sdk/contexts';
import { hasRole, hasPermission } from 'fauthy-next-sdk';
function AdminPanel() {
const claims = useClaims();
if (!hasRole(claims, 'admin')) {
return <div>Access denied</div>;
}
return <div>Admin content</div>;
}
function UserActions({ userId }: { userId: string }) {
const claims = useClaims();
return (
<div>
{hasPermission(claims, 'user:read') && (
<button>View User</button>
)}
{hasPermission(claims, 'user:write') && (
<button>Edit User</button>
)}
{hasPermission(claims, 'user:delete') && (
<button>Delete User</button>
)}
</div>
);
}API Routes Setup
This SDK uses API routes instead of Next.js middleware. See the API Routes Setup Guide for detailed instructions.
Quick Start:
// app/api/auth/me/route.ts
import { NextRequest, NextResponse } from "next/server";
import { handleMe } from "fauthy-next-sdk/utils/api-routes";
export async function GET(req: NextRequest) {
const secret = process.env.FAUTHY_SECRET!;
return handleMe(req, secret);
}Server-Side Usage
import { getSession, ensureValidSession, getClaimsFromSession, hasRole } from 'fauthy-next-sdk/utils/api-routes';
import { me } from 'fauthy-next-sdk';
// In a server component or API route
export async function AdminPage() {
const secret = process.env.FAUTHY_SECRET!;
// Get session from cookies
const session = await getSession(secret);
if (!session) {
redirect('/login');
}
// Ensure session is valid and refresh if needed
const validSession = await ensureValidSession(secret, session);
// Get claims from session
const claims = await getClaimsFromSession(validSession);
// Check permissions server-side
if (!hasRole(claims, 'admin')) {
return <div>Access denied</div>;
}
// Use the session to call server actions
const userResponse = await me(validSession);
const user = userResponse.data;
return <div>Admin content for {user.first_name}</div>;
}Types
import type {
User,
SessionData,
AccessClaims,
Options,
FormState,
Routes,
CookieOptions,
UserType
} from 'fauthy-next-sdk';
// AccessClaims interface for role and permission management
interface AccessClaims {
roles: string[];
permissions: string[];
}Module Exports
The SDK provides several entry points for different use cases:
- Main export:
fauthy-next-sdk- Core functionality - API Routes:
fauthy-next-sdk/utils/api-routes- API route handler utilities - Utils:
fauthy-next-sdk/utils/server- Server-side utility functions - Interfaces:
fauthy-next-sdk/interfaces- TypeScript types - Provider:
fauthy-next-sdk/provider- React components - Contexts:
fauthy-next-sdk/contexts- React contexts - Cookies:
fauthy-next-sdk/cookies- Cookie utilities - Errors:
fauthy-next-sdk/errors- Error classes
Environment Variables
FAUTHY_SECRET=your-secret-key
FAUTHY_API_URL=https://api.fauthy.com
FAUTHY_CLIENT_ID=your-client-id
FAUTHY_APP_ID=your-app-id
FAUTHY_CALLBACK_URL=https://your-app.com/auth/callbackAPI Reference
Utility Functions
decodeJWTClaims(token: string)
Decodes a JWT token and extracts claims.
- Parameters:
token- The JWT token to decode - Returns:
Promise<Record<string, any> | null>- Claims object or null if invalid
formatAccessClaims(claims: Record<string, any>)
Formats raw JWT claims into structured AccessClaims.
- Parameters:
claims- Raw claims from JWT token - Returns:
AccessClaims- Structured claims with roles and permissions
getClaimsFromSession(session: SessionData)
Extracts and formats claims from a server-side session.
- Parameters:
session- The session data - Returns:
Promise<AccessClaims>- Formatted claims
hasRole(claims: AccessClaims, roleName: string)
Checks if claims have a specific role.
- Parameters:
claims- The claims objectroleName- The role name to check for
- Returns:
boolean- True if claims have the role
hasAnyRole(claims: AccessClaims, roleNames: string[])
Checks if claims have any of the specified roles.
- Parameters:
claims- The claims objectroleNames- Array of role names to check for
- Returns:
boolean- True if claims have any of the roles
hasAllRoles(claims: AccessClaims, roleNames: string[])
Checks if claims have all of the specified roles.
- Parameters:
claims- The claims objectroleNames- Array of role names to check for
- Returns:
boolean- True if claims have all of the roles
hasPermission(claims: AccessClaims, permission: string)
Checks if claims have a specific permission.
- Parameters:
claims- The claims objectpermission- The permission to check for
- Returns:
boolean- True if claims have the permission
hasAnyPermission(claims: AccessClaims, permissions: string[])
Checks if claims have any of the specified permissions.
- Parameters:
claims- The claims objectpermissions- Array of permissions to check for
- Returns:
boolean- True if claims have any of the permissions
hasAllPermissions(claims: AccessClaims, permissions: string[])
Checks if claims have all of the specified permissions.
- Parameters:
claims- The claims objectpermissions- Array of permissions to check for
- Returns:
boolean- True if claims have all of the permissions
getClaimsPermissions(claims: AccessClaims)
Gets all permissions from claims.
- Parameters:
claims- The claims object - Returns:
string[]- Array of permissions from the claims
Claims Provider System
The Fauthy Next SDK includes a comprehensive claims provider system that enables role-based access control (RBAC) and permission-based access control (PBAC) for your application. This system allows you to manage user permissions and roles through JWT tokens and provide them to your React components.
Overview
The claims system consists of several key components:
- Claims Context - React context for providing claims to components
- Claims Provider - React component that wraps your app with claims data
- Utility Functions - Helper functions for checking roles and permissions
- JWT Integration - Automatic extraction of claims from JWT tokens
How It Works
1. Claims Structure
Claims are extracted from JWT tokens and structured as follows:
interface AccessClaims {
roles: string[]; // Array of role names
permissions: string[]; // Array of permission names
}2. JWT Token Processing
The system automatically processes JWT tokens to extract claims:
// JWT token contains claims like:
{
"roles": ["admin", "user"],
"permissions": ["read:users", "write:posts", "delete:comments"],
"sub": "user_uuid",
"exp": 1640995200
}3. Claims Extraction Flow
graph TD
A[JWT Token] --> B[decodeJWTClaims]
B --> C[formatAccessClaims]
C --> D[AccessClaims Object]
D --> E[ClaimsProvider]
E --> F[React Components]
F --> G[useClaims Hook]
G --> H[Role/Permission Checks]Usage Examples
Server-Side Claims Extraction
import { getClaimsFromSession } from '@studio-piot/fauthy-next-sdk';
// In a server component or API route
export async function MyServerComponent() {
const session = await getSession();
const claims = await getClaimsFromSession(session);
// Check if user has admin role
const isAdmin = await hasRole(claims, 'admin');
return (
<div>
{isAdmin && <AdminPanel />}
</div>
);
}Client-Side Claims Provider
import { ClaimsProvider, useClaims } from '@studio-piot/fauthy-next-sdk';
// Wrap your app with ClaimsProvider
function App({ children, initialClaims }) {
return (
<ClaimsProvider claims={initialClaims}>
{children}
</ClaimsProvider>
);
}
// Use claims in components
function MyComponent() {
const claims = useClaims();
// Check permissions
const canEdit = claims.permissions.includes('write:posts');
return (
<div>
{canEdit && <EditButton />}
</div>
);
}Role-Based Rendering
import { hasRole, hasPermission } from '@studio-piot/fauthy-next-sdk';
function Dashboard({ claims }) {
return (
<div>
{/* Show admin-only content */}
{hasRole(claims, 'admin') && (
<AdminSection />
)}
{/* Show content for users with specific permission */}
{hasPermission(claims, 'read:analytics') && (
<AnalyticsWidget />
)}
{/* Show content for multiple roles */}
{hasAnyRole(claims, ['admin', 'moderator']) && (
<ModerationTools />
)}
</div>
);
}Permission-Based Access Control
import { hasAllPermissions } from '@studio-piot/fauthy-next-sdk';
function UserManagement({ claims }) {
// Require multiple permissions
const canManageUsers = hasAllPermissions(claims, [
'read:users',
'write:users',
'delete:users'
]);
if (!canManageUsers) {
return <AccessDenied />;
}
return <UserManagementPanel />;
}Integration with Fauthy Provider
The claims system integrates seamlessly with the main Fauthy provider:
import { FauthyProvider, ClaimsProvider } from '@studio-piot/fauthy-next-sdk';
function RootLayout({ children, user, claims }) {
return (
<FauthyProvider user={user}>
<ClaimsProvider claims={claims}>
{children}
</ClaimsProvider>
</FauthyProvider>
);
}Custom Claims
The system also supports custom claims beyond roles and permissions:
interface User {
// ... other fields
custom_claims?: {
[key: string]: string;
};
}
// Access custom claims
function MyComponent({ user }) {
const department = user.custom_claims?.department;
const level = user.custom_claims?.level;
return (
<div>
<h1>Welcome, {user.first_name}</h1>
<p>Department: {department}</p>
<p>Level: {level}</p>
</div>
);
}Best Practices
- Server-Side Validation: Always validate permissions on the server side, not just the client
- Graceful Degradation: Handle cases where claims might be missing or incomplete
- Performance: Use the claims provider to avoid repeated JWT decoding
- Security: Never trust client-side permission checks alone
// Good: Server-side validation
export async function deleteUser(userId: string) {
const session = await getSession();
const claims = await getClaimsFromSession(session);
if (!hasPermission(claims, 'delete:users')) {
throw new Error('Insufficient permissions');
}
// Proceed with deletion
}
// Bad: Client-side only
function DeleteButton({ userId }) {
const claims = useClaims();
if (!hasPermission(claims, 'delete:users')) {
return null; // This can be bypassed!
}
return <button onClick={() => deleteUser(userId)}>Delete</button>;
}Error Handling
The claims system includes comprehensive error handling:
import { useClaims } from '@studio-piot/fauthy-next-sdk';
function MyComponent() {
try {
const claims = useClaims();
// Use claims safely
} catch (error) {
// Handle case where ClaimsProvider is missing
console.error('ClaimsProvider not found:', error);
return <div>Claims not available</div>;
}
}This claims provider system provides a robust foundation for implementing fine-grained access control in your Next.js applications while maintaining security and performance.
