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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@djangocfg/api

v2.1.231

Published

Auto-generated TypeScript API client with React hooks, SWR integration, and Zod validation for Django REST Framework backends

Downloads

7,071

Readme

@djangocfg/api

Core authentication API client and auth system for DjangoCFG applications.

Part of DjangoCFG — modern Django framework for production-ready SaaS applications.

Install

pnpm add @djangocfg/api

What's Inside

This package provides everything needed for authentication and user management:

  • API Client - Type-safe client for Django cfg_accounts API
  • Auth System - Complete authentication module with contexts, hooks, and utilities
  • JWT Management - Automatic token refresh and storage
  • OAuth Integration - GitHub OAuth with callback handling
  • Two-Factor Authentication - TOTP-based 2FA setup and verification
  • Server Middleware - Proxy middleware for Next.js
  • Shared Storage - Authentication storage used by all extensions

Package Structure

src/
├── generated/
│   ├── cfg_accounts/       # Generated API client (accounts, profiles, OAuth)
│   │   ├── api/            # API class with all endpoints
│   │   ├── schemas/        # Zod validation schemas
│   │   └── types/          # TypeScript types
│   └── cfg_totp/           # Generated TOTP/2FA client
│       ├── api/            # TOTP device, setup, verification endpoints
│       ├── schemas/        # TOTP-specific schemas
│       └── types/          # TOTP types
└── auth/
    ├── context/            # AuthProvider, AccountsProvider
    ├── hooks/              # useAuth, useAuthGuard, useGithubAuth, useTwoFactor, etc.
    ├── middlewares/        # Next.js proxy middleware
    └── utils/              # Validation, errors, logger, analytics

Entry Points

| Entry | Import | Description | |-------|--------|-------------| | Main | @djangocfg/api | Server-safe exports (API client, fetchers, schemas, types) | | Hooks | @djangocfg/api/hooks | Client-only SWR hooks for data fetching | | Auth | @djangocfg/api/auth | Client-only auth system (providers, hooks) | | Auth Server | @djangocfg/api/auth/server | Server-safe auth utilities (middleware) |

API Client

Pre-configured API instance with automatic JWT token management:

import { api } from '@djangocfg/api';

// Authentication
await api.accounts.login({ email, password });
await api.accounts.logout();
await api.accounts.register({ email, password, username });

// Profile
const profile = await api.accounts.profileRetrieve();
await api.accounts.profileUpdate({ first_name: 'John' });

// Password
await api.accounts.passwordChange({ old_password, new_password });
await api.accounts.passwordReset({ email });
await api.accounts.passwordResetConfirm({ token, password });

// OAuth
await api.accounts.oauthCallback({ provider: 'github', code });

Shared Authentication Storage

All DjangoCFG extensions use shared authentication storage from this package:

// Extensions automatically access the same auth tokens
import { apiSupport } from '@djangocfg/ext-support';
import { apiPayments } from '@djangocfg/ext-payments';

// All API clients share the same authentication state
// Login once, authenticated everywhere

This is handled automatically by createExtensionAPI() from @djangocfg/ext-base.

Auth Module

Complete authentication system with OTP, OAuth, and Two-Factor Authentication (2FA) support.

Authentication Flow

1. User enters email → OTP sent
2. User enters OTP code → Verify
   ├── If 2FA enabled → Show TOTP verification
   │   └── User enters 6-digit TOTP → Verify
   └── If no 2FA → Continue
3. Success screen with logo → Auto-redirect to dashboard

All authentication methods (OTP, OAuth, 2FA) show a success screen with your logo before redirecting.

Setup

// app/layout.tsx
import { AuthProvider } from '@djangocfg/api/auth';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <AuthProvider
          config={{
            routes: {
              auth: '/auth',
              defaultCallback: '/dashboard'
            }
          }}
        >
          {children}
        </AuthProvider>
      </body>
    </html>
  );
}

Available Hooks

import {
  useAuth,              // Main auth context (user, isAuthenticated, OTP methods)
  useAuthGuard,         // Protect routes (redirect if not authenticated)
  useAuthForm,          // Auth form state management (OTP + 2FA steps)
  useGithubAuth,        // GitHub OAuth integration
  useTwoFactor,         // 2FA verification (verify TOTP code)
  useTwoFactorSetup,    // 2FA setup flow (generate QR, verify, enable)
  useTwoFactorStatus,   // 2FA status check and disable
  useAutoAuth,          // Auto-authentication on mount
  useLocalStorage,      // localStorage helper
  useSessionStorage,    // sessionStorage helper
} from '@djangocfg/api/auth';

useAuth

Main authentication hook with OTP support:

'use client';
import { useAuth } from '@djangocfg/api/auth';

export function UserProfile() {
  const {
    user,              // UserProfile | null
    isAuthenticated,   // boolean
    isLoading,         // boolean
    requestOTP,        // (identifier, sourceUrl?) => Promise<{ success, message }>
    verifyOTP,         // (identifier, otp, sourceUrl?, redirectUrl?) => Promise<{ success, message, user? }>
    logout,            // () => void
  } = useAuth();

  if (isLoading) return <div>Loading...</div>;

  if (!isAuthenticated) {
    return <div>Please sign in</div>;
  }

  return (
    <div>
      <p>Welcome, {user?.email}!</p>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

useAuthGuard

Protect routes from unauthenticated access:

'use client';
import { useAuthGuard } from '@djangocfg/api/auth';

export default function DashboardPage() {
  const { isAllowed } = useAuthGuard({
    redirectTo: '/auth',
    requireAuth: true,
  });

  if (!isAllowed) return null;

  return <div>Protected Dashboard Content</div>;
}

useAuthForm

Manage authentication form state with OTP and 2FA support:

'use client';
import { useAuthForm } from '@djangocfg/api/auth';

export function OTPLoginForm() {
  const {
    // State
    identifier,        // Email address
    otp,               // 6-digit OTP code
    step,              // 'identifier' | 'otp' | '2fa' | '2fa-setup' | 'success'
    isLoading,
    error,
    acceptedTerms,
    isRateLimited,     // boolean - true when rate limited
    rateLimitLabel,    // string - formatted countdown e.g. "1:30" or "45s"

    // Setters
    setIdentifier,
    setOtp,
    setAcceptedTerms,

    // Handlers
    handleIdentifierSubmit,  // Request OTP
    handleOTPSubmit,         // Verify OTP
    handleResendOTP,         // Resend OTP
    handleBackToIdentifier,  // Go back to step 1

    // Utilities
    validateIdentifier,
  } = useAuthForm({
    sourceUrl: window.location.origin,
    requireTermsAcceptance: false, // Set true if terms/privacy links provided
    onIdentifierSuccess: (identifier) => {
      console.log('OTP sent to', identifier);
    },
    onOTPSuccess: () => {
      console.log('Login successful');
    },
  });

  if (step === 'identifier') {
    return (
      <form onSubmit={handleIdentifierSubmit}>
        <input
          type="email"
          value={identifier}
          onChange={(e) => setIdentifier(e.target.value)}
          placeholder="Enter email"
        />
        {error && <p className="text-red-500">{error}</p>}
        <button type="submit" disabled={isLoading}>
          {isLoading ? 'Sending...' : 'Send verification code'}
        </button>
      </form>
    );
  }

  return (
    <form onSubmit={handleOTPSubmit}>
      <p>Enter the code sent to {identifier}</p>
      <input
        type="text"
        value={otp}
        onChange={(e) => setOtp(e.target.value)}
        placeholder="000000"
        maxLength={6}
      />
      {error && <p className="text-red-500">{error}</p>}
      <button type="submit" disabled={isLoading || otp.length < 6}>
        {isLoading ? 'Verifying...' : 'Verify'}
      </button>
      <button type="button" onClick={handleResendOTP}>Resend</button>
      <button type="button" onClick={handleBackToIdentifier}>Back</button>
    </form>
  );
}

useAuthForm Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | sourceUrl | string | required | Application URL for OTP emails | | redirectUrl | string | - | URL to redirect after successful OTP verification | | requireTermsAcceptance | boolean | false | Require terms acceptance before submit | | onIdentifierSuccess | function | - | Callback after OTP sent | | onOTPSuccess | function | - | Callback after successful verification | | onError | function | - | Callback on error |

useGithubAuth

GitHub OAuth integration:

'use client';
import { useGithubAuth } from '@djangocfg/api/auth';

export function GithubLoginButton() {
  const {
    startGithubAuth,   // () => void - redirects to GitHub
    isLoading,         // boolean
    error,             // string | null
  } = useGithubAuth({
    sourceUrl: window.location.origin,
  });

  return (
    <button onClick={startGithubAuth} disabled={isLoading}>
      {isLoading ? 'Connecting...' : 'Continue with GitHub'}
    </button>
  );
}

OAuth callback is handled automatically by @djangocfg/layouts AuthLayout component.

useTwoFactor

Verify 2FA code during authentication:

'use client';
import { useTwoFactor } from '@djangocfg/api/auth';

export function TwoFactorVerify({ sessionId }: { sessionId: string }) {
  const {
    verify,        // (code: string) => Promise<void>
    isLoading,     // boolean
    error,         // string | null
  } = useTwoFactor({
    sessionId,
    onSuccess: (user) => console.log('2FA verified:', user),
    onError: (error) => console.error('2FA failed:', error),
    redirectUrl: '/dashboard',
    skipRedirect: false, // Set true if handling navigation manually
  });

  const [code, setCode] = useState('');

  return (
    <form onSubmit={(e) => { e.preventDefault(); verify(code); }}>
      <input
        type="text"
        value={code}
        onChange={(e) => setCode(e.target.value)}
        placeholder="000000"
        maxLength={6}
      />
      <button type="submit" disabled={isLoading || code.length < 6}>
        {isLoading ? 'Verifying...' : 'Verify'}
      </button>
    </form>
  );
}

useTwoFactorSetup

Setup 2FA for authenticated users:

'use client';
import { useTwoFactorSetup } from '@djangocfg/api/auth';

export function TwoFactorSetup() {
  const {
    // State
    qrCode,        // Base64 QR code image
    secret,        // Manual entry secret
    isEnabled,     // Current 2FA status
    isLoading,
    error,

    // Actions
    startSetup,    // () => Promise<void> - generates QR code
    verifySetup,   // (code: string) => Promise<void> - enables 2FA
    disable,       // () => Promise<void> - disables 2FA
    checkStatus,   // () => Promise<boolean> - refresh status
  } = useTwoFactorSetup({
    onSetupComplete: () => console.log('2FA enabled successfully'),
    onDisabled: () => console.log('2FA disabled'),
    onError: (error) => console.error('2FA setup error:', error),
  });

  if (isEnabled) {
    return (
      <div>
        <p>Two-factor authentication is enabled</p>
        <button onClick={disable}>Disable 2FA</button>
      </div>
    );
  }

  if (qrCode) {
    return (
      <div>
        <img src={qrCode} alt="2FA QR Code" />
        <p>Secret: {secret}</p>
        <input placeholder="Enter code from app" />
        <button onClick={() => verifySetup('123456')}>Verify & Enable</button>
      </div>
    );
  }

  return <button onClick={startSetup}>Set up 2FA</button>;
}

useTwoFactorStatus

Check 2FA status and disable 2FA for authenticated users:

'use client';
import { useTwoFactorStatus } from '@djangocfg/api/auth';

export function TwoFactorStatus() {
  const {
    // State
    has2FAEnabled,  // boolean | null - current 2FA status
    devices,        // TwoFactorDevice[] - list of TOTP devices
    isLoading,
    error,

    // Actions
    fetchStatus,    // () => Promise<void> - refresh status
    disable2FA,     // (code: string) => Promise<boolean> - disable with TOTP code
    clearError,     // () => void
  } = useTwoFactorStatus();

  useEffect(() => {
    fetchStatus();
  }, [fetchStatus]);

  if (has2FAEnabled) {
    return (
      <div>
        <p>2FA is enabled</p>
        <p>Devices: {devices.length}</p>
        <button onClick={() => disable2FA('123456')}>Disable 2FA</button>
      </div>
    );
  }

  return <p>2FA is not enabled</p>;
}

Server Components & API Routes

Use fetchers for server-side data fetching:

import { Fetchers, api } from '@djangocfg/api';

// Server Component
export default async function ProfilePage() {
  const profile = await Fetchers.getAccountsProfileRetrieve(api);

  return <div>{profile.email}</div>;
}

// API Route
export async function GET() {
  try {
    const profile = await Fetchers.getAccountsProfileRetrieve(api);
    return Response.json(profile);
  } catch (error) {
    return Response.json({ error: 'Failed to fetch profile' }, { status: 500 });
  }
}

Server Middleware

Proxy middleware for Django backend:

// middleware.ts
import { proxyMiddleware } from '@djangocfg/api/auth/server';
import { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  // Proxies /media/* and /api/* to Django backend
  // Automatically forwards cookies and headers
  return proxyMiddleware(request);
}

export const config = {
  matcher: ['/media/:path*', '/api/:path*'],
};

Client Hooks (SWR)

Use SWR hooks for reactive data fetching in client components:

'use client';
import { useAccountsProfileRetrieve, useAccountsProfileUpdate } from '@djangocfg/api/hooks';

export function Profile() {
  const { data: profile, isLoading, error, mutate } = useAccountsProfileRetrieve();
  const { trigger: updateProfile } = useAccountsProfileUpdate();

  const handleUpdate = async () => {
    await updateProfile({ first_name: 'John' });
    mutate(); // Revalidate data
  };

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <p>Email: {profile?.email}</p>
      <button onClick={handleUpdate}>Update Profile</button>
    </div>
  );
}

Validation Schemas

Zod schemas for runtime validation:

import { Schemas } from '@djangocfg/api';

// Validate API responses
const profile = Schemas.UserProfileSchema.parse(data);

// Validate form data
const loginData = Schemas.LoginRequestSchema.parse({
  email: '[email protected]',
  password: 'password123',
});

TypeScript Types

Full type safety for all API operations:

import type {
  UserProfile,
  LoginRequest,
  RegisterRequest,
  OAuthProvider,
  OAuthCallbackRequest,
} from '@djangocfg/api';

// Or use namespace
import type { CfgAccountsTypes } from '@djangocfg/api';
type Profile = CfgAccountsTypes.UserProfile;
type LoginReq = CfgAccountsTypes.LoginRequest;

Extension Packages

Extensions are now in separate packages with their own API clients that share authentication:

| Extension | Package | Description | |-----------|---------|-------------| | Newsletter | @djangocfg/ext-newsletter | Newsletter subscription and campaigns | | Knowledge Base | @djangocfg/ext-knowbase | Documentation, chat, RAG-powered AI | | Leads | @djangocfg/ext-leads | Lead capture and contact forms | | Payments | @djangocfg/ext-payments | Payment processing and subscriptions | | Support | @djangocfg/ext-support | Support tickets and helpdesk |

Extension Usage

// Extensions automatically use shared auth from @djangocfg/api
import { apiSupport } from '@djangocfg/ext-support';
import { apiPayments } from '@djangocfg/ext-payments';
import { apiLeads } from '@djangocfg/ext-leads';

// All authenticated automatically if user is logged in
const tickets = await apiSupport.tickets.list();
const payments = await apiPayments.payments.list();
const leads = await apiLeads.leads.list();

See individual extension documentation for details.

Error Handling

import { handleError, formatError } from '@djangocfg/api/auth';

try {
  await api.accounts.login({ email, password });
} catch (error) {
  handleError(error, (formattedError) => {
    console.error('Login failed:', formattedError);
    // formattedError has consistent structure:
    // { message: string, code?: string, details?: any }
  });
}

Analytics Integration

Auth events are automatically tracked when analytics is enabled:

// Automatic tracking for:
// - AUTH_LOGIN_SUCCESS
// - AUTH_LOGOUT
// - AUTH_SESSION_EXPIRED
// - AUTH_TOKEN_REFRESH
// - AUTH_OAUTH_START
// - AUTH_OAUTH_SUCCESS
// - AUTH_OAUTH_FAIL
// - AUTH_2FA_SETUP_START
// - AUTH_2FA_SETUP_COMPLETE
// - AUTH_2FA_VERIFY_SUCCESS
// - AUTH_2FA_VERIFY_FAIL

Analytics setup is handled by @djangocfg/layouts package.

Environment Variables

# Required
NEXT_PUBLIC_API_URL=http://localhost:8000

# OAuth (optional)
NEXT_PUBLIC_GITHUB_CLIENT_ID=your_github_client_id

# Static build (optional)
NEXT_PUBLIC_STATIC_BUILD=false

Development

# Generate API client from Django OpenAPI schema
make generate

# Build package
make build

# Watch mode
pnpm dev

Requirements

  • Next.js >= 15
  • React >= 19
  • SWR (peer dependency)
  • Zod (bundled for validation)

License

MIT

Links