npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

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-sdk

Usage

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/callback

API 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 object
    • roleName - 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 object
    • roleNames - 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 object
    • roleNames - 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 object
    • permission - 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 object
    • permissions - 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 object
    • permissions - 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:

  1. Claims Context - React context for providing claims to components
  2. Claims Provider - React component that wraps your app with claims data
  3. Utility Functions - Helper functions for checking roles and permissions
  4. 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

  1. Server-Side Validation: Always validate permissions on the server side, not just the client
  2. Graceful Degradation: Handle cases where claims might be missing or incomplete
  3. Performance: Use the claims provider to avoid repeated JWT decoding
  4. 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.