oauth-callback
TypeScript icon, indicating that this package has built-in type declarations

1.0.0 • Public • Published

OAuth Callback

npm version npm downloads MIT License TypeScript

A lightweight local HTTP server for handling OAuth 2.0 authorization callbacks in Node.js, Deno, and Bun applications. Perfect for CLI tools, desktop applications, and development environments that need to capture OAuth authorization codes.

OAuth Callback Demo

Features

  • 🚀 Multi-runtime support - Works with Node.js 18+, Deno, and Bun
  • 🔒 Secure localhost-only server for OAuth callbacks
  • Minimal dependencies - Only requires open package
  • 🎯 TypeScript support out of the box
  • 🛡️ Comprehensive OAuth error handling with detailed error classes
  • 🔄 Automatic server cleanup after callback
  • 🎪 Clean success pages with animated checkmark
  • 🎨 Customizable HTML templates with placeholder support
  • 🚦 AbortSignal support for programmatic cancellation
  • 📝 Request logging and debugging callbacks
  • 🌐 Modern Web Standards APIs (Request/Response/URL)

Installation

bun add oauth-callback

Or with npm:

npm install oauth-callback

Quick Start

import { getAuthCode, OAuthError } from "oauth-callback";

// Simple usage
const result = await getAuthCode(
  "https://example.com/oauth/authorize?client_id=xxx&redirect_uri=http://localhost:3000/callback",
);
console.log("Authorization code:", result.code);

Usage Examples

Basic OAuth Flow

import { getAuthCode, OAuthError } from "oauth-callback";

async function authenticate() {
  const authUrl =
    "https://github.com/login/oauth/authorize?" +
    new URLSearchParams({
      client_id: "your_client_id",
      redirect_uri: "http://localhost:3000/callback",
      scope: "user:email",
      state: "random_state_string",
    });

  try {
    const result = await getAuthCode(authUrl);
    console.log("Authorization code:", result.code);
    console.log("State:", result.state);

    // Exchange code for access token
    // ... your token exchange logic here
  } catch (error) {
    if (error instanceof OAuthError) {
      console.error("OAuth error:", error.error);
      console.error("Description:", error.error_description);
    } else {
      console.error("Unexpected error:", error);
    }
  }
}

Custom Port Configuration

import { getAuthCode } from "oauth-callback";

const result = await getAuthCode({
  authorizationUrl: authUrl,
  port: 8080, // Use custom port (default: 3000)
  timeout: 60000, // Custom timeout in ms (default: 30000)
});

Handling Different OAuth Providers

// Google OAuth
const googleAuth = await getAuthCode(
  "https://accounts.google.com/o/oauth2/v2/auth?" +
    new URLSearchParams({
      client_id: process.env.GOOGLE_CLIENT_ID,
      redirect_uri: "http://localhost:3000/callback",
      response_type: "code",
      scope: "openid email profile",
      access_type: "offline",
    }),
);

// Microsoft OAuth
const microsoftAuth = await getAuthCode(
  "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?" +
    new URLSearchParams({
      client_id: process.env.MICROSOFT_CLIENT_ID,
      redirect_uri: "http://localhost:3000/callback",
      response_type: "code",
      scope: "user.read",
      response_mode: "query",
    }),
);

Advanced Usage

// With custom HTML templates and logging
const result = await getAuthCode({
  authorizationUrl: authUrl,
  port: 3000,
  hostname: "127.0.0.1", // Bind to specific IP
  successHtml: "<h1>Success! You can close this window.</h1>",
  errorHtml: "<h1>Error: {{error_description}}</h1>",
  onRequest: (req) => {
    console.log(`Received request: ${req.method} ${req.url}`);
  },
});

// With cancellation support
const controller = new AbortController();

// Cancel after 10 seconds
setTimeout(() => controller.abort(), 10000);

try {
  const result = await getAuthCode({
    authorizationUrl: authUrl,
    signal: controller.signal,
  });
} catch (error) {
  if (error.message === "Operation aborted") {
    console.log("Authorization was cancelled");
  }
}

API Reference

getAuthCode(input)

Starts a local HTTP server and opens the authorization URL in the user's browser.

Parameters

  • input (string | GetAuthCodeOptions): Either a string containing the OAuth authorization URL, or an options object with:
    • authorizationUrl (string): The OAuth authorization URL
    • port (number): Port for the local server (default: 3000)
    • hostname (string): Hostname to bind the server to (default: "localhost")
    • callbackPath (string): URL path for the OAuth callback (default: "/callback")
    • timeout (number): Timeout in milliseconds (default: 30000)
    • openBrowser (boolean): Whether to open browser automatically (default: true)
    • successHtml (string): Custom HTML to display on successful authorization
    • errorHtml (string): Custom HTML to display on authorization error
    • signal (AbortSignal): AbortSignal for cancellation support
    • onRequest (function): Callback fired when a request is received (for logging/debugging)

Returns

Promise that resolves to:

{
  code: string;        // Authorization code
  state?: string;      // State parameter (if provided)
  [key: string]: any;  // Additional query parameters
}

Throws

  • OAuthError: When the OAuth provider returns an error (always thrown for OAuth errors)
  • Error: For timeout or other unexpected errors

OAuthError

Custom error class for OAuth-specific errors.

class OAuthError extends Error {
  error: string; // OAuth error code
  error_description?: string; // Human-readable error description
  error_uri?: string; // URI with error information
}

How It Works

  1. Server Creation: Creates a temporary HTTP server on the specified port
  2. Browser Launch: Opens the authorization URL in the user's default browser
  3. Callback Handling: Waits for the OAuth provider to redirect back with the authorization code
  4. Cleanup: Automatically closes the server after receiving the callback
  5. Result: Returns the authorization code and any additional parameters

Security Considerations

  • The server only accepts connections from localhost
  • Server is closed immediately after receiving the callback
  • No data is stored persistently
  • State parameter validation should be implemented by the application

Running the Examples

Interactive Demo (No Setup Required)

Try the library instantly with the built-in demo that includes a mock OAuth server:

# Run the demo - no credentials needed!
bun run example:demo

# Run without opening browser (for CI/testing)
bun run examples/demo.ts --no-browser

The demo showcases:

  • Dynamic client registration (simplified OAuth 2.0 DCR)
  • Complete authorization flow with mock provider
  • Multiple scenarios (success, access denied, invalid scope)
  • Custom HTML templates for success/error pages
  • Token exchange and API usage simulation

Real OAuth Examples

GitHub OAuth

For testing with GitHub OAuth:

# Set up GitHub OAuth App credentials
export GITHUB_CLIENT_ID="your_client_id"
export GITHUB_CLIENT_SECRET="your_client_secret"

# Run the GitHub example
bun run example:github

This example demonstrates:

  • Setting up OAuth with GitHub
  • Handling the authorization callback
  • Exchanging the code for an access token
  • Using the token to fetch user information

Notion MCP with Dynamic Client Registration

For testing with Notion's Model Context Protocol server:

# No credentials needed - uses Dynamic Client Registration!
bun run example:notion

This example demonstrates:

  • Dynamic Client Registration (OAuth 2.0 DCR) - no pre-configured client ID/secret needed
  • Integration with Model Context Protocol (MCP) servers
  • Automatic client registration with the authorization server
  • Using the MCP SDK's OAuth capabilities

Development

# Install dependencies
bun install

# Run tests
bun test

# Build
bun run build

# Run examples
bun run example:demo    # Interactive demo
bun run example:github  # GitHub OAuth example
bun run example:notion  # Notion MCP example with Dynamic Client Registration

Requirements

  • Node.js 18+ (for native Request/Response support), Deno, or Bun 1.0+
  • A registered OAuth application with a provider
  • Redirect URI configured as http://localhost:[port]/callback

Common Issues

Port Already in Use

If port 3000 is already in use, specify a different port:

const result = await getAuthCode({ authorizationUrl: authUrl, port: 8080 });

Firewall Warnings

On first run, your OS may show a firewall warning. Allow the connection for localhost only.

Browser Doesn't Open

If the browser doesn't open automatically, manually navigate to the authorization URL.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is released under the MIT License. Feel free to use it in your projects, modify it to suit your needs, and share it with others. We believe in open source and hope this tool makes OAuth integration easier for everyone!

Related Projects

  • MCP Client Generator - Generate TypeScript clients from MCP server specifications. Perfect companion for building MCP-enabled applications with OAuth support (npm).
  • React Starter Kit - Full-stack React application template with authentication, including OAuth integration examples.

Backers

Support this project by becoming a backer. Your logo will show up here with a link to your website.

              

Support

Found a bug or have a question? Please open an issue on the GitHub issue tracker and we'll be happy to help. If this project saves you time and you'd like to support its continued development, consider becoming a sponsor. Every bit of support helps maintain and improve this tool for the community. Thank you!

Package Sidebar

Install

npm i oauth-callback

Weekly Downloads

250

Version

1.0.0

License

MIT

Unpacked Size

125 kB

Total Files

19

Last publish

Collaborators

  • koistya