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

@the-forgebase/web-auth

v0.0.0-alpha.23

Published

Framework-agnostic web authentication SDK for ForgeBase with SSR support

Readme

ForgeBase Web Auth SDK

A framework-agnostic web authentication SDK for ForgeBase with SSR support.

Features

  • 🌐 Framework-agnostic - works with any JavaScript framework
  • 🖥️ Server-side rendering (SSR) support
  • 🔄 Automatic token refresh
  • 🍪 Cookie and localStorage support
  • 📱 Responsive to different environments
  • 🔒 Secure authentication flows
  • 🔄 Always fresh user data from the server
  • 🧩 Framework-specific integrations (React, Angular, Next.js, Nitro)
  • 🔄 Support for both Next.js Pages Router and App Router
  • 🚀 Angular integration with signals and standalone components
  • 🌐 Nitro framework support (Nuxt, Analog.js, etc.)
  • ⚡ TypeScript support

Installation

npm install @forgebase/web-auth
# or
yarn add @forgebase/web-auth

Basic Usage

Standalone Usage

import { ForgebaseWebAuth, StorageType } from '@forgebase/web-auth';

// Create a new instance
const auth = new ForgebaseWebAuth({
  apiUrl: 'https://api.example.com',
  storageType: StorageType.COOKIE, // or LOCAL_STORAGE or MEMORY
  useCookies: true, // Use cookies for authentication
  withCredentials: true, // Include credentials in requests
});

// Register a new user
await auth.register({
  email: '[email protected]',
  password: 'securePassword123',
  name: 'John Doe',
});

// Login
await auth.login({
  email: '[email protected]',
  password: 'securePassword123',
});

// Get the current user (from memory)
const user = auth.getCurrentUser(); // Note: This is deprecated

// Get the current user (always fetches fresh data from server)
const user = await auth.getUser();

// Check if authenticated
const isAuthenticated = auth.isAuthenticated();

// Logout
await auth.logout();

// Get the API instance for making authenticated requests
const api = auth.api;

// Make an authenticated request
const response = await api.get('/protected-endpoint');

// Get auth interceptors to apply to another axios instance
const authInterceptors = auth.getAuthInterceptors();

// Apply auth interceptors to your own axios instance
const myAxios = axios.create({ baseURL: 'https://api.example.com' });
auth.applyAuthInterceptors(myAxios);

React Integration

import React from 'react';
import { ForgebaseWebAuth, AuthProvider, useAuth, StorageType } from '@forgebase/web-auth';

// Create auth instance
const auth = new ForgebaseWebAuth({
  apiUrl: 'https://api.example.com',
  storageType: StorageType.COOKIE,
});

// App component
function App() {
  return (
    <AuthProvider auth={auth}>
      <Router>
        <Routes>
          <Route path="/login" element={<LoginPage />} />
          <Route path="/register" element={<RegisterPage />} />
          <Route
            path="/profile"
            element={
              <ProtectedRoute>
                <ProfilePage />
              </ProtectedRoute>
            }
          />
        </Routes>
      </Router>
    </AuthProvider>
  );
}

// Login component
function LoginPage() {
  const { login, isLoading, error } = useAuth();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      await login({ email, password });
      // Redirect to profile page
    } catch (err) {
      // Error is handled by the hook
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
      <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" />
      <button type="submit" disabled={isLoading}>
        {isLoading ? 'Loading...' : 'Login'}
      </button>
      {error && <p>{error.message}</p>}
    </form>
  );
}

// Protected route component
function ProtectedRoute({ children }) {
  const { isAuthenticated, isLoading } = useAuth();

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

  if (!isAuthenticated) {
    return <Navigate to="/login" />;
  }

  return children;
}

Framework Integrations

Next.js Integration with SSR

Pages Router

// _app.tsx
import { AppProps } from 'next/app';
import { ForgebaseWebAuth, AuthProvider, ServerAuthState } from '@forgebase/web-auth';

// Create auth instance
const auth = new ForgebaseWebAuth({
  apiUrl: process.env.NEXT_PUBLIC_API_URL,
  storageType: 'cookie',
  cookieDomain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN,
});

function MyApp({ Component, pageProps }: AppProps) {
  // Extract auth state from pageProps
  const { user, accessToken, refreshToken, ...restPageProps } = pageProps as ServerAuthState & any;

  return (
    <AuthProvider auth={auth} initialUser={user} initialAccessToken={accessToken} initialRefreshToken={refreshToken}>
      <Component {...restPageProps} />
    </AuthProvider>
  );
}

export default MyApp;

// pages/profile.tsx
import { GetServerSideProps } from 'next';
import { withAuth, useAuth } from '@forgebase/web-auth';

export const getServerSideProps: GetServerSideProps = withAuth(
  {
    authConfig: {
      apiUrl: process.env.NEXT_PUBLIC_API_URL,
      storageType: 'cookie',
    },
    redirectUnauthenticated: '/login',
  },
  async (context, auth, authState) => {
    // You can make authenticated API calls here
    // const api = auth.api;
    // const data = await api.get('/some-protected-endpoint');

    return {
      props: {
        // Additional props
      },
    };
  }
);

function ProfilePage() {
  const { user, logout } = useAuth();

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

export default ProfilePage;

App Router

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { authMiddleware } from '@forgebase/web-auth';

export function middleware(request: NextRequest) {
  return authMiddleware(request, {
    authConfig: {
      apiUrl: process.env.NEXT_PUBLIC_API_URL || '',
      storageType: 'cookie',
      secureCookies: process.env.NODE_ENV === 'production',
    },
    redirectUnauthenticated: '/login',
    publicPaths: ['/login', '/register'],
    authPaths: ['/dashboard', '/profile'],
  });
}

// app/layout.tsx
import { ReactNode } from 'react';
import { getAppRouterAuthProps } from '@forgebase/web-auth';
import ClientAuthProvider from './components/ClientAuthProvider';

export default function RootLayout({ children }: { children: ReactNode }) {
  // Get auth props from server
  const authProps = getAppRouterAuthProps();

  return (
    <html lang="en">
      <body>
        <ClientAuthProvider initialUser={authProps.user} initialAccessToken={authProps.accessToken} initialRefreshToken={authProps.refreshToken}>
          {children}
        </ClientAuthProvider>
      </body>
    </html>
  );
}

// app/components/ClientAuthProvider.tsx
('use client');

import { ReactNode } from 'react';
import { AuthProvider, ForgebaseWebAuth, User } from '@forgebase/web-auth';

// Create auth instance on the client
const auth = new ForgebaseWebAuth({
  apiUrl: process.env.NEXT_PUBLIC_API_URL || '',
  storageType: 'cookie',
});

interface ClientAuthProviderProps {
  children: ReactNode;
  initialUser: User | null;
  initialAccessToken?: string;
  initialRefreshToken?: string;
}

export default function ClientAuthProvider({ children, initialUser, initialAccessToken, initialRefreshToken }: ClientAuthProviderProps) {
  return (
    <AuthProvider auth={auth} initialUser={initialUser} initialAccessToken={initialAccessToken} initialRefreshToken={initialRefreshToken}>
      {children}
    </AuthProvider>
  );
}

// app/dashboard/page.tsx
import { protectRoute, getCurrentUser } from '@forgebase/web-auth';
import DashboardClient from './DashboardClient';

export default function DashboardPage() {
  // Protect this route - will redirect if not authenticated
  protectRoute();

  // Get the current user from server
  const user = getCurrentUser();

  return (
    <div>
      <h1>Dashboard</h1>
      <p>Welcome, {user?.name || 'User'}!</p>

      {/* Pass to client component for interactive features */}
      <DashboardClient initialData={user} />
    </div>
  );
}

Angular Integration

The SDK provides a modern Angular integration with support for signals and standalone components.

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideForgebaseAuth } from '@forgebase/web-auth';
import { StorageType } from '@forgebase/web-auth';

export const appConfig: ApplicationConfig = {
  providers: [
    provideForgebaseAuth({
      apiUrl: 'https://api.example.com',
      storageType: StorageType.COOKIE,
      secureCookies: true,
    }),
  ],
};

// login.component.ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ForgebaseAuthService } from '@forgebase/web-auth';

@Component({
  selector: 'app-login',
  standalone: true,
  imports: [FormsModule],
  template: `
    <div>
      <h1>Login</h1>
      <form (ngSubmit)="onSubmit()">
        <div>
          <label for="email">Email</label>
          <input type="email" id="email" [(ngModel)]="email" name="email" required />
        </div>
        <div>
          <label for="password">Password</label>
          <input type="password" id="password" [(ngModel)]="password" name="password" required />
        </div>
        <button type="submit" [disabled]="isLoading()">{{ isLoading() ? 'Loading...' : 'Login' }}</button>
      </form>
      @if (currentError()) {
      <div class="error">{{ currentError().message }}</div>
      }
    </div>
  `,
})
export class LoginComponent {
  email = '';
  password = '';

  // Inject the auth service
  constructor(private authService: ForgebaseAuthService) {}

  // Access signals directly
  isLoading = this.authService.isLoading;
  currentError = this.authService.currentError;

  async onSubmit() {
    try {
      await this.authService.login({
        email: this.email,
        password: this.password,
      });
      // Navigate to dashboard
    } catch (error) {
      // Error is handled by the service
    }
  }
}

// auth.guard.ts
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { ForgebaseAuthService } from '@forgebase/web-auth';

export const authGuard: CanActivateFn = () => {
  const authService = inject(ForgebaseAuthService);
  const router = inject(Router);

  if (authService.isAuthenticated()) {
    return true;
  }

  // Redirect to login
  return router.parseUrl('/login');
};

Nitro Framework Integration

The SDK provides integration with Nitro-based frameworks like Nuxt and Analog.js.

// server/middleware/auth.ts (Nuxt example)
import { defineEventHandler } from 'h3';
import { nitroAuthMiddleware } from '@forgebase/web-auth';

export default defineEventHandler((event) => {
  nitroAuthMiddleware(event, {
    authConfig: {
      apiUrl: process.env.API_URL || '',
      storageType: 'cookie',
      secureCookies: process.env.NODE_ENV === 'production'
    },
    redirectUnauthenticated: '/login',
    publicPaths: ['/login', '/register'],
    authPaths: ['/dashboard', '/profile']
  });
});

// server/api/protected.ts
import { defineEventHandler } from 'h3';
import {
  protectNitroRoute,
  getNitroUser,
  createNitroAuthenticatedFetch
} from '@forgebase/web-auth';

export default defineEventHandler(async (event) => {
  // Protect this route
  protectNitroRoute(event);

  // Get the current user
  const user = getNitroUser(event);

  // Create an authenticated fetch
  const authenticatedFetch = createNitroAuthenticatedFetch(event);

  // Make an authenticated request
  const response = await authenticatedFetch('https://api.example.com/data');
  const data = await response.json();

  return {
    user,
    data
  };
});

// pages/login.vue (Nuxt example)
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';

const email = ref('');
const password = ref('');
const error = ref(null);
const loading = ref(false);
const router = useRouter();

async function login() {
  loading.value = true;
  error.value = null;

  try {
    const response = await $fetch('/api/login', {
      method: 'POST',
      body: {
        email: email.value,
        password: password.value
      }
    });

    if (response.success) {
      router.push('/dashboard');
    }
  } catch (err) {
    error.value = err.message || 'Login failed';
  } finally {
    loading.value = false;
  }
}
</script>

<template>
  <div>
    <h1>Login</h1>
    <form @submit.prevent="login">
      <div>
        <label for="email">Email</label>
        <input type="email" id="email" v-model="email" required>
      </div>
      <div>
        <label for="password">Password</label>
        <input type="password" id="password" v-model="password" required>
      </div>
      <button type="submit" :disabled="loading">{{ loading ? 'Loading...' : 'Login' }}</button>
    </form>
    <p v-if="error" class="error">{{ error }}</p>
  </div>
</template>

Authentication Flows

Email Verification

// Send verification email
const { sendVerificationEmail } = useAuth();
await sendVerificationEmail('[email protected]', 'https://example.com/verify');

// Verify email
const { verifyEmail } = useAuth();
await verifyEmail(userId, verificationCode);

Password Reset

// Request password reset
const { forgotPassword } = useAuth();
await forgotPassword('[email protected]', 'https://example.com/reset-password');

// Verify reset token
const { auth } = useAuth();
const isValid = await auth.verifyResetToken(userId, resetToken);

// Reset password
const { resetPassword } = useAuth();
await resetPassword(userId, resetToken, 'newSecurePassword123');

Storage Options

The SDK supports different storage mechanisms:

import { ForgebaseWebAuth, StorageType } from '@forgebase/web-auth';

// Use cookies (default)
const auth1 = new ForgebaseWebAuth({
  apiUrl: 'https://api.example.com',
  storageType: StorageType.COOKIE,
  cookieDomain: 'example.com',
  secureCookies: true,
  httpOnlyCookies: true,
  sameSite: 'lax',
});

// Use localStorage
const auth2 = new ForgebaseWebAuth({
  apiUrl: 'https://api.example.com',
  storageType: StorageType.LOCAL_STORAGE,
});

// Use in-memory storage (for SSR or when storage is not available)
const auth3 = new ForgebaseWebAuth({
  apiUrl: 'https://api.example.com',
  storageType: StorageType.MEMORY,
});

// Use custom storage
const auth4 = new ForgebaseWebAuth({
  apiUrl: 'https://api.example.com',
  storage: myCustomStorage, // Implements AuthStorage interface
});

SSR Detection

The SDK automatically detects if it's running in an SSR environment and adjusts its behavior accordingly:

  • In SSR environments, it won't try to access browser-specific APIs
  • It will use cookies for authentication in SSR environments
  • It provides utilities for hydrating the auth state from server to client

Using the Axios Instance

The SDK exposes the configured axios instance with all authentication interceptors:

// Get the axios instance
const { getApi } = useAuth();
const api = getApi();

// Make authenticated API calls
const response = await api.get('/protected-resource');

Error Handling

import { AuthErrorType } from '@forgebase/web-auth';

try {
  await auth.login({ email, password });
} catch (error) {
  switch (error.type) {
    case AuthErrorType.INVALID_CREDENTIALS:
      // Handle invalid credentials
      break;
    case AuthErrorType.VERIFICATION_REQUIRED:
      // Handle verification required
      break;
    case AuthErrorType.NETWORK_ERROR:
      // Handle network error
      break;
    case AuthErrorType.SSR_ERROR:
      // Handle SSR-specific error
      break;
    default:
      // Handle other errors
      break;
  }
}

License

MIT