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

@benbraide/auth-service-nextjs

v1.1.1

Published

Next.js/React component for integrating iframe-based account switcher with authentication service

Readme

@benbraide/auth-service-nextjs

Next.js/React component library for integrating iframe-based account switcher with authentication service.

Features

Full TypeScript Support - Complete type definitions for all components and hooks ✅ SSR Compatible - Works seamlessly with Next.js server-side rendering ✅ Interactive Dialogs - Built-in support for confirm, prompt, and alert dialogs ✅ Auto-Resize - Iframe automatically adjusts height based on content ✅ Tree-Shakeable - Modern ESM and CJS builds with optimized bundle size ✅ Zero Dependencies - Only peer dependencies on React 18+

Installation

npm install @benbraide/auth-service-nextjs

Quick Start

1. Wrap your app with AccountSwitcherProvider

// app/layout.tsx
import { AccountSwitcherProvider } from '@benbraide/auth-service-nextjs';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <AccountSwitcherProvider
          backendUrl={process.env.NEXT_PUBLIC_API_URL!}
          authServiceUrl="https://auth.yourdomain.com"
          onSessionChange={(session) => {
            console.log('Session changed:', session);
          }}
        >
          {children}
        </AccountSwitcherProvider>
      </body>
    </html>
  );
}

2. Use the AccountSwitcher component

// components/Header.tsx
'use client';

import { AccountSwitcher, useSession } from '@benbraide/auth-service-nextjs';

export function Header() {
  const { currentUser, isAuthenticated } = useSession();

  return (
    <header className="flex items-center justify-between p-4">
      <h1>My App</h1>

      {isAuthenticated && (
        <div className="flex items-center gap-4">
          <span>Welcome, {currentUser?.name}!</span>
          <AccountSwitcher />
        </div>
      )}
    </header>
  );
}

3. Create API route for token generation

The package expects a /api/account-switcher/token endpoint that returns the widget token:

// app/api/account-switcher/token/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  try {
    // Call your backend (Laravel/Node/etc.) to get the widget token
    const response = await fetch(`${process.env.BACKEND_URL}/api/account-switcher/token`, {
      headers: {
        'Accept': 'application/json',
      },
      credentials: 'include',
    });

    const data = await response.json();

    return NextResponse.json(data);
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to fetch token' },
      { status: 500 }
    );
  }
}

Components

AccountSwitcherProvider

Context provider that manages session state and iframe communication.

Props:

interface AccountSwitcherConfig {
  backendUrl: string;                              // Required: Your backend API URL
  authServiceUrl?: string;                         // Optional: Auth service URL
  onSessionChange?: (session: Session) => void;    // Optional: Session change callback
  onAccountChange?: (user: User) => void;          // Optional: Account change callback
  onError?: (error: Error) => void;                // Optional: Error callback
  debug?: boolean;                                 // Optional: Enable debug logging

  // Dialog configuration
  dialogs?: {
    enabled?: boolean;                             // Default: true
    closeOnOverlayClick?: boolean;                 // Default: true
    closeOnEscape?: boolean;                       // Default: true
  };

  // Custom dialog handlers
  onConfirmRequest?: (payload: ConfirmPayload) => Promise<boolean>;
  onPromptRequest?: (payload: PromptPayload) => Promise<string | null>;
  onAlertRequest?: (payload: AlertPayload) => Promise<void>;

  // Auto-resize configuration
  autoResize?: boolean;                            // Default: true
  minHeight?: number;                              // Default: 200
  maxHeight?: number | null;                       // Default: null (unlimited)
  onResize?: (height: number) => void;             // Optional: Resize callback

  // Navigation handlers (optional - default: window.location.href)
  onNavigateToAddAccount?: (url: string) => void;     // Handle add account navigation
  onNavigateToManageAccount?: (url: string) => void;  // Handle account management navigation
  onNavigateToAvatarUpdate?: (url: string) => void;   // Handle avatar update navigation
}

AccountAvatar

Compact, clickable avatar component for NAV bars that displays the current user's avatar and toggles the account switcher visibility.

Props:

interface AccountAvatarProps {
  size?: number;                                  // Avatar diameter in pixels (default: 40)
  className?: string;                             // Additional CSS classes
  style?: React.CSSProperties;                    // Custom inline styles
  targetId?: string;                              // ID of element to toggle (IFRAME container)
  onClick?: () => void;                           // Custom click handler
  onAvatarClick?: (user: User | null) => void;   // Callback with user data on click
}

Features:

  • Displays user avatar (image or initials) when logged in
  • Shows generic profile icon when logged out
  • Automatically syncs with session changes
  • Toggles target element visibility (typically IFRAME container)
  • Outside click and ESC key support for closing popup
  • Smooth hover and active animations

Example:

// In your NAV component
'use client';

import { AccountAvatar } from '@benbraide/auth-service-nextjs';

export function Navbar() {
  return (
    <nav className="navbar">
      <div className="logo">My App</div>

      <div className="nav-items">
        {/* Avatar that toggles the dropdown */}
        <AccountAvatar
          size={40}
          targetId="account-switcher-dropdown"
          onAvatarClick={(user) => console.log('Clicked:', user?.name)}
        />
      </div>
    </nav>

    {/* Hidden dropdown with AccountSwitcher */}
    <div
      id="account-switcher-dropdown"
      style={{
        display: 'none',
        position: 'absolute',
        top: '60px',
        right: '20px',
        zIndex: 1000,
      }}
    >
      <AccountSwitcher width={320} height={400} />
    </div>
  );
}

AccountSwitcher

Iframe component that displays the account switcher widget.

Props:

interface AccountSwitcherProps {
  className?: string;                             // Optional: CSS class
  position?: 'top-left' | 'top-right' |          // Optional: Position
             'bottom-left' | 'bottom-right';
  width?: number;                                // Optional: Width in pixels
  height?: number;                               // Optional: Height in pixels
}

Hooks

useSession()

Returns current session state.

const {
  isAuthenticated,
  currentUser,
  accounts,
  isLoading,
  error
} = useSession();

useUser()

Returns current user object.

const user = useUser();

useAccountSwitcher()

Returns account switcher methods.

const {
  switchAccount,
  addAccount,
  manageAccount,
  updateAvatar,
  logoutAccount,
  logoutAll,
  refresh
} = useAccountSwitcher();

// Switch to a different account
await switchAccount('user-uuid-here');

// Add new account
await addAccount();

// Navigate to account management page
await manageAccount();

// Navigate to avatar update page
await updateAvatar();

// Logout specific account
await logoutAccount('user-uuid');

// Logout all accounts
await logoutAll();

// Refresh session
await refresh();

Advanced Usage

Custom Dialog Handlers

Use your own UI library (e.g., SweetAlert2, Radix UI):

<AccountSwitcherProvider
  backendUrl={process.env.NEXT_PUBLIC_API_URL!}
  onConfirmRequest={async (payload) => {
    const result = await Swal.fire({
      title: payload.title,
      text: payload.message,
      icon: payload.variant === 'danger' ? 'warning' : 'question',
      showCancelButton: true,
      confirmButtonText: payload.confirmText || 'OK',
    });
    return result.isConfirmed;
  }}
>
  {children}
</AccountSwitcherProvider>

Event Handlers

<AccountSwitcherProvider
  backendUrl={process.env.NEXT_PUBLIC_API_URL!}
  onSessionChange={(session) => {
    if (session.isAuthenticated) {
      // Load user data
      fetchUserData(session.currentUser.uuid);
    }
  }}
  onAccountChange={(user) => {
    // Reload page or refresh data
    window.location.reload();
  }}
  onError={(error) => {
    toast.error(error.message);
  }}
>
  {children}
</AccountSwitcherProvider>

Custom Navigation Handlers

Override default navigation behavior for account flows:

<AccountSwitcherProvider
  backendUrl={process.env.NEXT_PUBLIC_API_URL!}
  onNavigateToAddAccount={(url) => {
    // Use Next.js router instead of window.location
    router.push(url);
  }}
  onNavigateToManageAccount={(url) => {
    // Open in new tab
    window.open(url, '_blank');
  }}
  onNavigateToAvatarUpdate={(url) => {
    // Custom modal implementation
    openAvatarModal(url);
  }}
>
  {children}
</AccountSwitcherProvider>

Debug Mode

Enable verbose logging:

<AccountSwitcherProvider
  backendUrl={process.env.NEXT_PUBLIC_API_URL!}
  debug={process.env.NODE_ENV === 'development'}
>
  {children}
</AccountSwitcherProvider>

TypeScript Types

interface User {
  uuid: string;
  name: string;
  email: string;
  avatar_url?: string;
  created_at?: string;
}

interface Session {
  isAuthenticated: boolean;
  currentUser: User | null;
  accounts: User[];
}

Backend Integration

Your backend should implement these endpoints:

GET /api/account-switcher/token

Generate widget embed token.

Response:

{
  "token": "eyJ...",
  "embed_url": "https://auth.example.com/widgets/embed?token=eyJ...",
  "expires_at": "2025-10-02 01:30:00"
}

POST /api/account-switcher/sync-session (Optional)

Sync session after account switch.

Request:

{
  "auth_token": "eyJ...",
  "user_uuid": "user-uuid"
}

License

MIT

Author

Ben Braide