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

@pixpilot/pkce-auth-chrome

v0.10.0

Published

Chrome Extension PKCE authentication package with seamless OAuth 2.0 integration

Downloads

24

Readme

@pixpilot/pkce-auth-chrome

PKCE OAuth 2.0 authentication for Chrome extensions with automatic state management.

Installation

pnpm add @pixpilot/pkce-auth-chrome

Quick Start

Recommended: Class-Based API

The easiest way to use this library. Configure once and use for both steps:

import { ChromePKCEAuthClient } from '@pixpilot/pkce-auth-chrome';

// Configure once with shared settings
const auth = new ChromePKCEAuthClient({
  loginUrl: 'https://oauth.example.com/authorize',
  redirectUrl: chrome.runtime.getURL('callback.html'),
  exchangeUrl: 'https://oauth.example.com/token',
  clientId: 'your_client_id',
  scope: 'read write',
});

// In background script: start flow
await auth.startAuthFlow();

// In callback.html: handle callback
const params = new URLSearchParams(window.location.search);
const tokens = await auth.handleAuthCallback({
  authCode: params.get('code')!,
  receivedState: params.get('state')!,
});

Alternative: Individual Functions

Use individual functions if you need more control:

import { handleAuthCallback, startAuthFlow } from '@pixpilot/pkce-auth-chrome';

// 1. Start auth flow (generates PKCE, saves state, opens auth tab)
await startAuthFlow({
  loginUrl: 'https://oauth.example.com/authorize',
  redirectUrl: chrome.runtime.getURL('callback.html'),
  exchangeUrl: 'https://oauth.example.com/token',
  clientId: 'your_client_id',
  scope: 'read write',
});

// 2. In callback.html, exchange code for tokens
const params = new URLSearchParams(window.location.search);
const tokens = await handleAuthCallback({
  authCode: params.get('code')!,
  receivedState: params.get('state')!,
  exchangeUrl: 'https://oauth.example.com/token',
});

Complete Example

manifest.json:

{
  "permissions": ["storage", "tabs"],
  "host_permissions": ["https://api.example.com/*"]
}

background.js (start flow):

import { ChromePKCEAuthClient } from '@pixpilot/pkce-auth-chrome';

const auth = new ChromePKCEAuthClient({
  loginUrl: 'https://oauth.example.com/authorize',
  redirectUrl: chrome.runtime.getURL('callback.html'),
  exchangeUrl: 'https://oauth.example.com/token',
  clientId: 'your_client_id',
  scope: 'read write',
});

await auth.startAuthFlow();

callback.html:

import { ChromePKCEAuthClient } from '@pixpilot/pkce-auth-chrome';

const auth = new ChromePKCEAuthClient({
  loginUrl: 'https://oauth.example.com/authorize',
  redirectUrl: chrome.runtime.getURL('callback.html'),
  exchangeUrl: 'https://oauth.example.com/token',
  clientId: 'your_client_id',
  scope: 'read write',
});

const params = new URLSearchParams(window.location.search);
if (params.get('code') && params.get('state')) {
  await auth.handleAuthCallback({
    authCode: params.get('code')!,
    receivedState: params.get('state')!,
  });
  window.close();
}

API

Auth Flow

  • startAuthFlow(config) - Start OAuth flow
    • config.allowHttpLocalhost?: boolean - Allow HTTP localhost for development per RFC 8252 (default: false)
  • handleAuthCallback(config) - Exchange code for tokens
    • config.authCode: string - The authorization code from the OAuth provider
    • config.receivedState: string - The state parameter from the OAuth provider
    • config.exchangeUrl: string - The OAuth token exchange endpoint URL
    • config.clientId?: string - Optional OAuth client ID for token exchange
    • config.redirectUrl?: string - Optional redirect URI for token exchange
    • config.allowHttpLocalhost?: boolean - Allow HTTP localhost for development per RFC 8252

Token Management

  • getTokenData() - Get tokens with metadata
  • saveTokens(accessToken, refreshToken, expiresIn?, tokenType?) - Save tokens
  • isTokenExpired() - Check if token is expired
  • clearAuthData() - Clear all auth data

Storage

  • saveAuthState(state, codeVerifier) - Save auth state
  • getAuthState(state) - Get auth state by state parameter
  • markCodeAsUsed(code) - Mark authorization code as used
  • isCodeUsed(code) - Check if code was used

Tab Management

  • openAuthTab(url) - Open URL in new tab

URL Validation

This package uses secure-by-default URL validation to protect against common OAuth vulnerabilities.

Security Defaults

Default behavior (secure by default):

  • validateLoginUrl & validateRedirectUrl: HTTPS and chrome-extension:// only
  • validateExchangeUrl: HTTPS only

💡 RFC 8252 Compliance: Set allowHttpLocalhost: true for development to enable OAuth 2.0 standard localhost support.

Secure Defaults (Production-Ready)

import { startAuthFlow } from '@pixpilot/pkce-auth-chrome';

// Default validators are secure (HTTPS-only)
await startAuthFlow({
  loginUrl: 'https://auth.example.com/authorize', // ✓ Secure
  redirectUrl: chrome.runtime.getURL('callback.html'),
  exchangeUrl: 'https://oauth.example.com/token',
  // allowHttpLocalhost: false (default) - Production-safe
});

// For local development, enable RFC 8252 localhost support
await startAuthFlow({
  loginUrl: 'http://localhost:3000/authorize', // ✓ Allowed per RFC 8252
  redirectUrl: chrome.runtime.getURL('callback.html'),
  exchangeUrl: 'https://oauth.example.com/token',
  allowHttpLocalhost: true, // OAuth 2.0 for Native Apps standard
});

✅ Allowed URLs:

  • HTTPS URLs (production APIs)
  • chrome-extension:// URLs (your extension)
  • http://localhost or http://127.0.0.1 (local dev servers)

❌ Blocked URLs:

  • Other HTTP URLs (security risk)

Production Mode (Recommended)

Production extensions should use the secure defaults (no localhost allowed):

import { startAuthFlow } from '@pixpilot/pkce-auth-chrome';

await startAuthFlow({
  loginUrl: 'https://auth.example.com/authorize',
  redirectUrl: chrome.runtime.getURL('callback.html'),
  exchangeUrl: 'https://auth.example.com/token',
  // allowHttpLocalhost: false (default) - Production-safe
});

Or use explicit production validators:

import { getProductionValidator, startAuthFlow } from '@pixpilot/pkce-auth-chrome';

await startAuthFlow({
  loginUrl: 'https://auth.example.com/authorize',
  redirectUrl: chrome.runtime.getURL('callback.html'),
  exchangeUrl: 'https://auth.example.com/token',
  validateLoginUrl: getProductionValidator(), // No localhost allowed
  validateExchangeUrl: getProductionValidator(), // CRITICAL: Secure token exchange
});

Or use specific validators:

import { isHttpsOrChromeExtensionUrl, isHttpsUrl } from '@pixpilot/pkce-auth-chrome';

await startAuthFlow({
  loginUrl: 'https://auth.example.com/authorize',
  validateLoginUrl: isHttpsOrChromeExtensionUrl, // HTTPS or chrome-extension://
  validateExchangeUrl: isHttpsUrl, // HTTPS only
});

Available Validators

import {
  getDefaultValidator,
  getProductionValidator,
  isChromeExtensionUrl,
  isHttpsOrChromeExtensionOrLocalhostUrl,
  isHttpsOrChromeExtensionUrl,
  isHttpsUrl,
} from '@pixpilot/pkce-auth-chrome';

// Recommended: Production-safe validator with auto-detection
const validator = getProductionValidator();

// Development: Default with production warnings
const devValidator = getDefaultValidator();

// Custom combinations
await startAuthFlow({
  loginUrl: 'https://auth.example.com',
  validateLoginUrl: isHttpsUrl, // HTTPS only
  validateRedirectUrl: isHttpsOrChromeExtensionUrl, // HTTPS or chrome-extension://
  validateExchangeUrl: isHttpsOrChromeExtensionOrLocalhostUrl, // Dev mode
});

Custom Validators

import type { UrlValidator } from '@pixpilot/pkce-auth-chrome';

// Your custom validation logic
const myValidator: UrlValidator = async (url: string) =>
  url.startsWith('https://trusted-domain.com');

await startAuthFlow({
  loginUrl: 'https://trusted-domain.com/auth',
  validateLoginUrl: myValidator,
});

Security Best Practices

  1. Never use localhost validation in production builds

    // ❌ BAD: Allows HTTP interception in production
    await startAuthFlow({
      exchangeUrl: 'http://localhost:3000/token',
    });
    
    // ✅ GOOD: Use getProductionValidator() or explicit HTTPS
    await startAuthFlow({
      exchangeUrl: 'https://auth.example.com/token',
      validateExchangeUrl: getProductionValidator(),
    });
  2. Token exchange URL is most critical

    • The exchangeUrl receives your authorization code
    • Must be HTTPS in production to prevent code interception
    • Consider using isHttpsUrl for strictest validation
  3. Use environment detection

    import { startAuthFlow } from '@pixpilot/pkce-auth-chrome';
    
    // Auto-detects production vs development
    await startAuthFlow({
      loginUrl: 'https://auth.example.com/authorize',
      redirectUrl: chrome.runtime.getURL('callback.html'),
      exchangeUrl: 'https://auth.example.com/token',
      allowHttpLocalhost: process.env.NODE_ENV !== 'production',
    });

Security Features

  • ✅ Secure URL validation (HTTPS, chrome-extension://, localhost in dev)
  • ✅ PKCE with SHA-256 challenge
  • ✅ CSRF protection with state parameter
  • ✅ Authorization code replay prevention
  • ✅ State expiration (10 minutes)
  • ✅ Token expiration tracking
  • ✅ Automatic cleanup of used codes
  • ✅ Open redirect protection
  • ✅ Credential leak prevention

License

MIT