Skip to content

Releases: kriasoft/oauth-callback

v1.2.1

20 Aug 11:37
150f30e

Choose a tag to compare

What's Changed

  • Add comprehensive VitePress documentation site by @koistya in #22
  • refactor(server): Introduce base class and add runtime types by @7heMech in #1

New Contributors

Full Changelog: v1.2.0...v1.2.1

v1.2.0

16 Aug 22:48
0a03dc7

Choose a tag to compare

🎉 Improved Module Organization for MCP SDK Integration

This release reorganizes the package exports to provide better clarity and separation between core OAuth functionality and Model Context Protocol (MCP) SDK-specific features.

🚀 What's New

Dedicated MCP Module Export

The MCP SDK integration features are now available through a dedicated export path, making it clear that these are specialized for MCP usage:

// New: Direct import from dedicated MCP module
import { browserAuth, fileStore } from "oauth-callback/mcp";

// Also available via namespace for flexibility
import { mcp } from "oauth-callback";
const authProvider = mcp.browserAuth({ store: mcp.fileStore() });

Complete Type Exports

All MCP-related TypeScript types are now properly exported for advanced use cases:

  • BrowserAuthOptions - Configuration for browser OAuth flows
  • Tokens - OAuth token storage interface
  • TokenStore - Minimal storage interface
  • ClientInfo - Dynamic client registration data
  • OAuthSession - OAuth flow state
  • OAuthStore - Full OAuth state storage

🔄 Migration Guide

If you're using browserAuth in your project, update your imports:

Before:

import { browserAuth, fileStore } from "oauth-callback";

After:

import { browserAuth, fileStore } from "oauth-callback/mcp";

Core OAuth functionality remains unchanged:

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

✨ Benefits

  • Clearer Intent: Makes it explicit that browserAuth() is designed for MCP SDK integration
  • Better Organization: Separates core OAuth from MCP-specific features
  • Type Safety: All necessary types are now exported for custom implementations
  • Smaller Bundles: Applications can import only what they need

📦 Technical Details

  • Two separate bundles: dist/index.js (core) and dist/mcp.js (MCP features)
  • Each bundle is approximately 56KB
  • Full backward compatibility via namespace export
  • No breaking changes to core OAuth functionality

🐛 Fixes

  • Resolved missing type exports issue (#16)
  • Improved module boundaries and separation of concerns (#20)
  • Fixed Bun bundler crash when building multiple entry points

📚 Documentation

  • Updated all examples to use new import paths
  • Enhanced API documentation with module location indicators
  • Improved project structure documentation in CLAUDE.md

🙏 Acknowledgments

Thanks to the community for feedback on improving the module structure and making the MCP integration more intuitive!


Full Changelog: v1.1.0...v1.2.0

Installation

npm install [email protected]
# or
bun add [email protected]

Questions or Issues?

Please open an issue on our GitHub repository if you encounter any problems or have questions about the migration.

v1.1.0

16 Aug 21:10

Choose a tag to compare

🎉 Major Features

MCP SDK Integration

  • New browserAuth() provider: Drop-in OAuth provider for Model Context Protocol SDK with built-in Dynamic Client Registration support
  • Token storage system: Flexible token persistence with inMemoryStore() for ephemeral sessions and fileStore() for persistent storage
  • Automatic token management: Built-in token refresh, expiry tracking, and secure storage

✨ Enhancements

Improved Developer Experience

  • Enhanced TypeScript support: Added comprehensive MCP type definitions and interfaces
  • Better testing: Added extensive test coverage for browserAuth provider with 260+ lines of tests
  • Streamlined examples: Refactored Notion example to showcase Dynamic Client Registration with MCP SDK

Project Infrastructure

  • CI/CD pipeline: Added GitHub Actions workflow for automated testing across Node.js, Deno, and Bun runtimes
  • Cross-platform testing: Ensures compatibility with Node.js 18+, 20+, 22+, Deno, and Bun
  • Automated releases: NPM publishing workflow with provenance support

🔧 API Additions

New Exports

  • browserAuth() - MCP SDK-compatible OAuth provider
  • inMemoryStore() - Ephemeral token storage
  • fileStore() - Persistent file-based token storage
  • MCP type definitions for OAuth client providers

Storage API

// Ephemeral storage
const auth = browserAuth({ store: inMemoryStore() });

// Persistent storage
const auth = browserAuth({ store: fileStore() });

📚 Documentation

  • Added comprehensive CLAUDE.md project guide for AI assistants
  • Updated README with MCP SDK integration examples
  • Enhanced API documentation with token storage options

🏗️ Internal Improvements

  • Modularized codebase with separate auth, storage, and utils modules
  • Improved template build system with better error handling
  • Enhanced demo example with cleaner flow and better UX

🐛 Bug Fixes

  • Fixed template compilation issues with HTML escaping
  • Improved error handling in OAuth callback flows
  • Better cleanup of resources on process termination

📦 Dependencies

  • Updated to latest @modelcontextprotocol/sdk version
  • Added bun-types for improved Bun runtime support
  • Streamlined dev dependencies

Breaking Changes

None - This release maintains backward compatibility with v1.0.x

Migration Guide

No migration required. The new browserAuth() provider is an optional enhancement for MCP SDK users.

Contributors

  • @koistya - Lead development and MCP integration

For more details, see PR #2

v1.0.0

15 Aug 09:49

Choose a tag to compare

The OAuth Integration Challenge

Building OAuth 2.0 authorization flows in CLI tools, desktop applications, and development environments has historically been a complex and error-prone process. Developers face numerous challenges:

  • Complex Server Setup: Implementing a temporary HTTP server to capture OAuth callbacks requires boilerplate code
  • Multi-Runtime Support: Different JavaScript runtimes (Node.js, Deno, Bun) have different APIs and requirements
  • Error Handling: OAuth providers return various error formats that need proper parsing and handling
  • Security Concerns: Ensuring the callback server only accepts localhost connections and properly cleans up
  • User Experience: Providing clear feedback to users during the authorization process
  • Browser Integration: Automatically opening the authorization URL in the user's default browser

Introducing OAuth Callback

OAuth Callback is a lightweight, zero-configuration solution that eliminates these pain points. With just a few lines of code, you can implement a complete OAuth 2.0 authorization flow that works across all modern JavaScript runtimes.

import { getAuthCode } from "oauth-callback";

// That's it! Complete OAuth flow in one line
const { code } = await getAuthCode(
  "https://github.com/login/oauth/authorize?client_id=xxx",
);

Why OAuth Callback?

🚀 Universal Runtime Support

Works seamlessly across Node.js 18+, Deno, and Bun without any runtime-specific code. The library automatically detects and adapts to your environment.

🔒 Security First

  • Localhost-only server binding prevents external access
  • Automatic server cleanup after callback
  • State parameter support for CSRF protection
  • No data persistence or logging of sensitive information

⚡ Minimal Dependencies

Only requires the open package for browser integration. No heavy frameworks, no complex configurations.

🎯 Developer Experience

  • TypeScript support with full type definitions
  • Comprehensive error handling with OAuthError class
  • Clean, modern API using Web Standards (Request/Response/URL)
  • Detailed JSDoc comments for IDE autocomplete

Interactive Demo

Try it yourself without any setup! Our demo includes a mock OAuth server that simulates the complete authorization flow:

# No credentials needed - fully self-contained demo
bun run example:demo

# Or with npm
npm run example:demo

The demo showcases:

  • Dynamic Client Registration (OAuth 2.0 DCR)
  • Complete authorization flow with mock provider
  • Multiple scenarios (success, access denied, invalid scope)
  • Custom HTML templates with animated success page
  • Token exchange and API usage simulation

Real-World Examples

GitHub OAuth Integration

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

async function authenticateWithGitHub() {
  const authUrl =
    "https://github.com/login/oauth/authorize?" +
    new URLSearchParams({
      client_id: process.env.GITHUB_CLIENT_ID,
      redirect_uri: "http://localhost:3000/callback",
      scope: "user:email",
      state: crypto.randomUUID(), // CSRF protection
    });

  try {
    const result = await getAuthCode(authUrl);

    // Exchange code for access token
    const tokenResponse = await fetch(
      "https://github.com/login/oauth/access_token",
      {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          client_id: process.env.GITHUB_CLIENT_ID,
          client_secret: process.env.GITHUB_CLIENT_SECRET,
          code: result.code,
          state: result.state,
        }),
      },
    );

    const { access_token } = await tokenResponse.json();
    console.log("Successfully authenticated!");
    return access_token;
  } catch (error) {
    if (error instanceof OAuthError) {
      console.error(`OAuth error: ${error.error_description || error.error}`);
    }
    throw error;
  }
}

Google OAuth with Custom Configuration

const result = await getAuthCode({
  authorizationUrl:
    "https://accounts.google.com/o/oauth2/v2/auth?" +
    new URLSearchParams({
      client_id: process.env.GOOGLE_CLIENT_ID,
      redirect_uri: "http://localhost:8080/callback",
      response_type: "code",
      scope: "openid email profile",
      access_type: "offline", // Request refresh token
      prompt: "consent",
    }),
  port: 8080, // Custom port
  timeout: 60000, // 60 second timeout
  successHtml: `
    <html>
      <body style="font-family: system-ui; text-align: center; padding: 50px;">
        <h1>✅ Authorization Successful!</h1>
        <p>You can now close this window and return to the application.</p>
      </body>
    </html>
  `,
});

Dynamic Client Registration (No Pre-Configuration!)

For services that support OAuth 2.0 Dynamic Client Registration:

import { getAuthCode } from "oauth-callback";

// No client_id or client_secret needed!
const { client_id, client_secret } = await registerDynamicClient({
  client_name: "My Awesome App",
  redirect_uris: ["http://localhost:3000/callback"],
});

const result = await getAuthCode(
  `https://provider.com/authorize?client_id=${client_id}&redirect_uri=http://localhost:3000/callback`,
);

Key Features in v1.0.0

🎨 Customizable Success/Error Pages

Beautiful default templates with animated checkmarks, or bring your own:

await getAuthCode({
  authorizationUrl: authUrl,
  successHtml: "<h1>Welcome {{user}}!</h1>", // Supports placeholders
  errorHtml: "<h1>Error: {{error_description}}</h1>",
});

🚦 AbortSignal Support

Full cancellation support for programmatic control:

const controller = new AbortController();
setTimeout(() => controller.abort(), 10000); // Cancel after 10s

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

📝 Request Logging

Debug and monitor the authorization flow:

await getAuthCode({
  authorizationUrl: authUrl,
  onRequest: (req) => {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    console.log("Headers:", Object.fromEntries(req.headers.entries()));
  },
});

🌐 Modern Web Standards

Built on Web Standards APIs for maximum compatibility:

  • Request and Response objects
  • URL and URLSearchParams for URL manipulation
  • AbortController for cancellation
  • Native fetch for HTTP requests

Installation

# Bun (recommended)
bun add oauth-callback

# npm
npm install oauth-callback

# pnpm
pnpm add oauth-callback

# Yarn
yarn add oauth-callback

Getting Started

  1. Register your OAuth application with your provider
  2. Set the redirect URI to http://localhost:3000/callback (or your chosen port)
  3. Install the library and start coding:
import { getAuthCode } from "oauth-callback";

// Minimal setup
const { code } = await getAuthCode(
  "https://provider.com/authorize?client_id=xxx",
);

// With error handling
try {
  const { code, state } = await getAuthCode({
    authorizationUrl: authUrl,
    timeout: 30000,
  });

  // Exchange code for tokens
  const tokens = await exchangeCodeForTokens(code);
} catch (error) {
  if (error instanceof OAuthError) {
    // Handle OAuth-specific errors
    console.error("Authorization failed:", error.error_description);
  }
}

Performance

  • Startup time: < 50ms to create and start the server
  • Memory footprint: < 5MB for the entire process
  • Zero runtime dependencies: Only open for browser integration
  • Automatic cleanup: Server closes immediately after callback

Migration from Manual Implementation

Before (manual implementation):

// 50+ lines of boilerplate code
const server = http.createServer((req, res) => {
  const url = new URL(req.url, `http://localhost:3000`);
  if (url.pathname === "/callback") {
    const code = url.searchParams.get("code");
    const error = url.searchParams.get("error");
    // Handle response, close server, etc...
  }
});
server.listen(3000);
// Open browser, handle errors, timeouts...

After (with oauth-callback):

// Just 1 line!
const { code } = await getAuthCode(authUrl);

What's Next?

Planned Features for v1.1.0

  • PKCE (Proof Key for Code Exchange) support
  • Built-in token exchange helpers
  • Refresh token management
  • Multiple callback handling (for multi-account scenarios)
  • WebSocket support for real-time updates

Community Contributions Welcome!

We're actively looking for contributors to help with:

  • Additional provider examples
  • Documentation improvements
  • Testing on different platforms
  • Internationalization support

Breaking Changes from Pre-Release

None! This is our first stable release. The API is now considered stable and will follow semantic versioning.

Acknowledgments

Special thanks to our early adopters and contributors who helped shape this library:

  • The MCP (Model Context Protocol) community for testing and feedback
  • Early users who reported issues and suggested improvements
  • The open-source community for inspiration and support

Support

Read more