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

lbyte-authentication-service

v1.0.1

Published

Shared Authentication Service for React microfrontends (single-spa compatible)

Readme

LByte Authentication Service

A comprehensive authentication service library for React microfrontends using single-spa architecture. This library provides centralized authentication state management, HTTP client with automatic token handling, and reusable components.

🚀 Features

  • Centralized Auth State: React Context-based authentication state management
  • HTTP Client: Built-in API client with automatic token injection and refresh
  • TypeScript Support: Full type definitions included
  • Microfrontend Ready: Designed for single-spa and module federation
  • Token Management: Automatic token refresh and error handling
  • Testing Support: Comprehensive test coverage with Jest and RTL

📦 Installation

npm install lbyte-authentication-service

Peer Dependencies

npm install react react-dom

🔧 Basic Setup

1. Wrap your root application with AuthServiceProvider

// shell/root application
import React from 'react';
import { AuthServiceProvider } from 'lbyte-authentication-service';
import { AppRouter } from './router';

function App() {
  return (
    <AuthServiceProvider>
      <AppRouter />
    </AuthServiceProvider>
  );
}

export default App;

2. Use authentication in your components

// Any microfrontend component
import React from 'react';
import { useAuthService } from 'lbyte-authentication-service';

function LoginComponent() {
  const { isAuthenticated, user, setAuth, clearAuth } = useAuthService();

  const handleLogin = async () => {
    try {
      const response = await fetch('/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password })
      });
      
      const { token, user } = await response.json();
      
      setAuth({
        isAuthenticated: true,
        user: { id: user.id, name: user.name },
        token
      });
    } catch (error) {
      console.error('Login failed:', error);
    }
  };

  if (isAuthenticated) {
    return (
      <div>
        <h2>Welcome, {user?.name}!</h2>
        <button onClick={clearAuth}>Logout</button>
      </div>
    );
  }

  return (
    <div>
      <button onClick={handleLogin}>Login</button>
    </div>
  );
}

3. Use the API client for authenticated requests

import React, { useEffect, useState } from 'react';
import { useApiClient } from 'lbyte-authentication-service';

function ProfileComponent() {
  const [profile, setProfile] = useState(null);
  const apiClient = useApiClient();

  useEffect(() => {
    const fetchProfile = async () => {
      try {
        const response = await apiClient.get('/user/profile');
        const profileData = await response.json();
        setProfile(profileData);
      } catch (error) {
        console.error('Failed to fetch profile:', error);
      }
    };

    fetchProfile();
  }, [apiClient]);

  return (
    <div>
      {profile ? (
        <div>
          <h3>Profile</h3>
          <p>Email: {profile.email}</p>
          <p>Role: {profile.role}</p>
        </div>
      ) : (
        <p>Loading profile...</p>
      )}
    </div>
  );
}

🏗️ Advanced Usage

Custom API Client Configuration

import { apiClient } from 'lbyte-authentication-service';

// Configure base URL and default headers
apiClient.initialize(
  () => localStorage.getItem('token'), // Token getter
  () => {
    // Token expired handler
    localStorage.removeItem('token');
    window.location.href = '/login';
  },
  async () => {
    // Optional: Token refresh handler
    try {
      const refreshToken = localStorage.getItem('refreshToken');
      const response = await fetch('/api/auth/refresh', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ refreshToken })
      });
      
      if (response.ok) {
        const { token } = await response.json();
        localStorage.setItem('token', token);
        return true;
      }
      return false;
    } catch {
      return false;
    }
  }
);

Protected Routes

import React from 'react';
import { useAuthService } from 'lbyte-authentication-service';
import { Navigate } from 'react-router-dom';

function ProtectedRoute({ children }: { children: React.ReactNode }) {
  const { isAuthenticated } = useAuthService();
  
  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }
  
  return <>{children}</>;
}

// Usage
function App() {
  return (
    <Routes>
      <Route path="/login" element={<LoginPage />} />
      <Route 
        path="/dashboard" 
        element={
          <ProtectedRoute>
            <Dashboard />
          </ProtectedRoute>
        } 
      />
    </Routes>
  );
}

🧪 Testing

Testing Components with Auth Service

import React from 'react';
import { render, screen } from '@testing-library/react';
import { AuthServiceProvider } from 'lbyte-authentication-service';
import { MyComponent } from './MyComponent';

function renderWithAuth(ui: React.ReactElement) {
  return render(
    <AuthServiceProvider>
      {ui}
    </AuthServiceProvider>
  );
}

test('renders component with authentication', () => {
  renderWithAuth(<MyComponent />);
  expect(screen.getByText(/login/i)).toBeInTheDocument();
});

Mocking API Client

import { apiClient } from 'lbyte-authentication-service';

// Mock API client in tests
jest.mock('lbyte-authentication-service', () => ({
  ...jest.requireActual('lbyte-authentication-service'),
  useApiClient: () => ({
    get: jest.fn(),
    post: jest.fn(),
    put: jest.fn(),
    delete: jest.fn(),
  }),
}));

API Configuration

The library provides flexible base URL configuration for different environments and deployment scenarios.

Global Configuration (Recommended)

Configure the API base URL globally for all API calls:

import { setGlobalApiConfig } from '@your-org/lbyte-authentication-service';

// Set at application startup
setGlobalApiConfig({
  baseURL: 'https://api.example.com'
});

Per-instance Configuration

Create a custom ApiClient instance with specific configuration:

import { ApiClient } from '@your-org/lbyte-authentication-service';

const customApiClient = new ApiClient({
  baseURL: 'https://api.different.com'
});

Environment-based Configuration

Configure different base URLs for different environments:

import { setGlobalApiConfig } from '@your-org/lbyte-authentication-service';

// In your microfrontend's initialization
const getApiBaseURL = () => {
  if (window.location.hostname === 'localhost') {
    return 'http://localhost:3001';
  } else if (window.location.hostname.includes('staging')) {
    return 'https://staging-api.example.com';
  } else {
    return 'https://api.example.com';
  }
};

setGlobalApiConfig({
  baseURL: getApiBaseURL()
});

Runtime Configuration Updates

Update configuration at runtime if needed:

import { setGlobalApiConfig, getGlobalApiConfig } from '@your-org/lbyte-authentication-service';

// Get current configuration
const currentConfig = getGlobalApiConfig();
console.log('Current base URL:', currentConfig.baseURL);

// Update configuration
setGlobalApiConfig({
  ...currentConfig,
  baseURL: 'https://new-api.example.com'
});

API Reference

AuthService

Types

interface AuthState {
  isAuthenticated: boolean;
  user: null | { id: string; name: string };
  token: string | null;
}

interface AuthServiceContextProps extends AuthState {
  setAuth: (auth: Partial<AuthState>) => void;
  clearAuth: () => void;
}

useAuthService Hook

const {
  isAuthenticated, // boolean
  user,            // { id: string; name: string } | null
  token,           // string | null
  setAuth,         // (auth: Partial<AuthState>) => void
  clearAuth        // () => void
} = useAuthService();

API Client

Methods

// Basic HTTP methods
await apiClient.get('/endpoint');
await apiClient.post('/endpoint', data);
await apiClient.put('/endpoint', data);
await apiClient.delete('/endpoint');

// Generic request method
await apiClient.request('/endpoint', {
  method: 'PATCH',
  body: JSON.stringify(data),
  headers: { 'Custom-Header': 'value' }
});

Configuration

interface ApiClientConfig {
  baseURL?: string;
  defaultHeaders?: Record<string, string>;
}

🏢 Microfrontend Architecture

Single-SPA Integration

// root-config.js
import { registerApplication, start } from 'single-spa';

registerApplication({
  name: 'shell',
  app: () => import('./shell/shell.app.js'),
  activeWhen: '/',
});

registerApplication({
  name: 'mf-dashboard',
  app: () => import('./dashboard/dashboard.app.js'),
  activeWhen: '/dashboard',
});

start();
// shell.app.js
import React from 'react';
import ReactDOM from 'react-dom';
import { AuthServiceProvider } from 'lbyte-authentication-service';

function Shell() {
  return (
    <AuthServiceProvider>
      <div id="single-spa-application:shell">
        <nav>Navigation</nav>
        <main id="microfrontend-content" />
      </div>
    </AuthServiceProvider>
  );
}

export const mount = (props) => {
  ReactDOM.render(<Shell />, props.domElement);
};

Module Federation

// webpack.config.js
const ModuleFederationPlugin = require('@module-federation/webpack');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        dashboard: 'dashboard@http://localhost:3001/remoteEntry.js',
      },
      shared: {
        react: { singleton: true },
        'react-dom': { singleton: true },
        'lbyte-authentication-service': { singleton: true },
      },
    }),
  ],
};

🔒 Security Best Practices

  1. Token Storage: Use secure storage (httpOnly cookies) for production
  2. Token Refresh: Implement automatic token refresh logic
  3. HTTPS Only: Always use HTTPS in production
  4. CSRF Protection: Implement CSRF tokens for state-changing operations
  5. Input Validation: Validate all inputs on both client and server

🛠️ Development

Building the Library

npm run build

Running Tests

npm test
npm run test:watch

Linting and Formatting

npm run lint
npm run lint:fix
npm run format

📝 License

MIT

📋 Changelog

v1.0.1 (2025-09-11)

  • Fixed: ApiClient URL construction for full URLs with ports
  • Fixed: Automatic /api prefix being added to all requests
  • Enhanced: Smart URL concatenation that handles both full URLs and relative paths
  • Added: Comprehensive URL construction tests
  • Improved: Documentation with URL construction examples

v1.0.0 (2025-09-11)

  • Initial release
  • React Context-based authentication service
  • HTTP client with automatic token handling
  • TypeScript support
  • Single-spa and microfrontend compatibility
  • Comprehensive test coverage

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

📞 Support

For issues and questions, please open an issue on the GitHub repository.