Releases: kriasoft/oauth-callback
v1.2.1
v1.2.0
🎉 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 flowsTokens- OAuth token storage interfaceTokenStore- Minimal storage interfaceClientInfo- Dynamic client registration dataOAuthSession- OAuth flow stateOAuthStore- 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) anddist/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
🎉 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 andfileStore()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 providerinMemoryStore()- Ephemeral token storagefileStore()- 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
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
OAuthErrorclass - 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:demoThe 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:
RequestandResponseobjectsURLandURLSearchParamsfor URL manipulationAbortControllerfor cancellation- Native
fetchfor HTTP requests
Installation
# Bun (recommended)
bun add oauth-callback
# npm
npm install oauth-callback
# pnpm
pnpm add oauth-callback
# Yarn
yarn add oauth-callbackGetting Started
- Register your OAuth application with your provider
- Set the redirect URI to
http://localhost:3000/callback(or your chosen port) - 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
openfor 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
- 📚 Documentation
- 🐛 Issue Tracker
- 💬 Discussions
- 💰 [Sponsor](https://github.co...