OAuthTunnel is a lightweight proxy server for forwarding OAuth callbacks to your local backend during development.
Author: Arijit Banerjee
License: MIT
- Features
- Author
- Setup
- Usage
- Functionalities and Technologies Used
- From the Developer
- Tips
- Contributing
- License
- 🚀 Dynamic Routing: Forwards callbacks based on the
state
parameter, allowing flexible and dynamic routing during OAuth flows. - 🛠️ Development-Only: Specifically designed for local development environments to simplify OAuth integration without exposing your local server.
- 🐳 Docker Support: Easily deployable using Docker, making setup and teardown a breeze.
Author : Arijit Banerjee
About : Full Stack Web Developer | Cyber Security Enthusiast | Actor
Social Media :
Instagram
LinkedIn
GitHub
Website
Email: arijit.codes@gmail.com
- 🛠️ Clone the repo.
- 📦 Run
bun i
to install dependencies. - 🚀 Start the server with
docker compose up
.
-
Register the proxy server's callback URL (e.g.,
https://oauth.example.com/auth/google/callback
) with OAuth providers. Note thatoauth.example.com
is just an example subdomain. -
When initiating the OAuth flow in your Passport.js setup, include
localIP
,clientType
, andlocalPort
in thestate
parameter ifNODE_ENV
isdevelopment
. This setup is specifically for development environments. For example, your implementation of the OAuth provider auth route using Passport.js should look like this:router.get("/:provider", (req, res, next) => { const provider = req.params.provider; const clientType = req.query.client_type; // 'web' or 'mobile' let state = { clientType }; // Add development-specific data if (process.env.NODE_ENV === "development") { state = { ...state, localIP: process.env.LOCAL_IP || "192.168.xx.xx", localPort: process.env.LOCAL_PORT || 5000, }; } passport.authenticate(provider, { scope: oauthProviders[provider].scope, state: encodeURIComponent(JSON.stringify(state)), })(req, res, next); });
Stack
: MERN Stack (MongoDB, ExpressJS, ReactJS, NodeJS)
Technologies Used
: NodeJS, ExpressJS, ReactJS, MongoDB, Mongoose, Passport.js, JWT, Docker, Nginx, etc.
Functionalities
:
- 🌐 OAuth Providers: Supports multiple OAuth providers (Google, GitHub, etc.), making it easy to integrate with various authentication services.
- 🔄 Dynamic Callback Handling: Uses a subdomain to forward OAuth callbacks to the local backend during development, ensuring seamless integration.
- 🌍 Environment-Specific Logic: Configures different callback URLs for development and production environments, adapting to your deployment needs.
- 📡 Dynamic IP Handling: Updates local IP dynamically for forwarding callbacks, accommodating changes in your development environment.
This project aims to simplify OAuth authentication during local development by using a subdomain to handle callback URLs dynamically. It supports multiple OAuth providers and local authentication with JWT tokens.
I was working on implementing a Passport.js OAuth authentication system for a web and mobile application. The goal was to support multiple OAuth providers (e.g., Google, GitHub) and local email/password authentication, all while using JWT for session management instead of Passport sessions. The backend was built with Express.js, the web app with React, and the mobile app with React Native (Expo).
- Allow users to log in via OAuth providers (Google, GitHub, etc.) or local email/password.
- Use JWT tokens for authentication instead of Passport sessions.
- Support both web and mobile clients with a unified authentication flow.
- Avoid hardcoding callback URLs for each provider and make the system scalable for future OAuth providers.
- During development, the mobile app couldn’t connect to the backend running on localhost because it was on a different device.
- Using the local IP (e.g., 192.168.xx.xx) worked for the mobile app but caused issues with OAuth providers because they require a publicly accessible callback URL.
- OAuth providers (e.g., Google, GitHub) require a registered callback URL.
- Google allows multiple callback URLs but does not allow IP addresses (only localhost or top-level domain names).
- GitHub allows only one callback URL but does allow IP addresses.
- This made it impossible to use both localhost and a local IP for development without constantly updating the registered callback URL.
- The subdomain (https://oauth.example.com) would act as a proxy to forward OAuth callbacks to the local backend. Note that
oauth.example.com
is just an example subdomain. - The state parameter would include clientType (web/mobile), localIP (for development), and localPort.
- The callbackURL in the Passport strategy configuration would be set dynamically based on the environment (NODE_ENV).
- In development, the subdomain would forward callbacks to the local backend.
- In production, the callbackURL would be set to the production callback URL (e.g., https://api.production.com/auth/google/callback), which would come from environment variables.
- The local backend would expose an endpoint (/updateIP) to update the local IP stored in memory.
- Alternatively, the local IP could be set via an environment variable.
- The subdomain (https://oauth.example.com) will be registered as the callback URL with all OAuth providers only for development. Note that
oauth.example.com
is just an example subdomain. - It will forward callbacks to the local backend during development based on the clientType, localIP, and localPort in the state parameter.
- In production, the subdomain will not be used. Instead, the production server will handle everything directly, and no local IP will be sent or forwarded.
- The local backend will process the OAuth callback using passport.authenticate().
- It will generate a JWT and redirect to the appropriate client (web or mobile).
- In development, the callbackURL will be set to the subdomain, and the subdomain will forward requests to the local backend.
- In production, the callbackURL will be set to the production callback URL (e.g., https://api.production.com/auth/google/callback), which will come from environment variables.
- The local IP will be passed in the state parameter during development.
- The subdomain will use this IP to forward callbacks to the local backend.
- The subdomain is not yet set up or registered with OAuth providers.
- The subdomain API is not yet implemented.
- Set up the subdomain (https://oauth.example.com) and link it to the server. Note that
oauth.example.com
is just an example subdomain. - Implement the subdomain API to forward callbacks to the local backend during development.
- Register the subdomain as the callback URL with all OAuth providers.
- Test the entire flow in both development and production environments.
- Handle edge cases (e.g., missing profile data, invalid state parameters).
If you have any suggestions, please feel free to leave the suggestions. Constructive Criticism is always appreciated.
- To setup this project, clone it and run `bun i` to install dependencies.
- Create a file named .env in the root. You can use the .env.sample file as a reference for the ENV Variables that are needed for the app.
- Set Up the required Env Variables to be used in the app.
- Start the server with `docker compose up`.
OR, just build the Docker Image using the Dockerfile and enjoy.
PS: If you go with docker, use port 5000 in the build process.
We welcome contributions! Please see our CONTRIBUTING.md for guidelines on how to contribute to this project.
This project is licensed under the MIT License. See the LICENSE file for details.