
OAuth with Portless
OfficialFreeEasily configure OAuth for local development environments.
Free · Opens the source repo
What OAuth with Portless does
OAuth with Portless is a skill designed to streamline the integration of OAuth providers into local development setups. Many developers encounter issues when trying to use OAuth with the default .localhost subdomains, as these are often rejected by major providers like Google and Apple due to their strict domain validation rules. This skill addresses these challenges by allowing users to configure valid top-level domains (TLDs) for their local applications, ensuring that redirect URIs are accepted by OAuth providers.
The skill works by enabling developers to run their applications on real, valid domains instead of the restrictive .localhost subdomains. By using the --tld option with Portless, developers can serve their applications on domains such as .dev, .app, or any other TLD in the Public Suffix List. This not only resolves common errors like "redirect_uri_mismatch" and "invalid redirect" but also provides a more realistic testing environment that closely mirrors production setups.
This skill is particularly beneficial for teams working on applications that require OAuth authentication from multiple providers. By using a custom TLD under a domain they control, teams can ensure consistent redirect URIs across all developers, simplifying the setup process and minimizing potential errors. Moreover, developers can configure their OAuth providers with the appropriate redirect URIs, allowing for seamless integration of sign-in functionalities during local development.
Overall, OAuth with Portless is an essential tool for developers looking to implement OAuth in a local environment without running into domain-related issues. It simplifies the process of setting up and testing OAuth integrations, making it a valuable addition to any developer's toolkit.
When to use it
Use this skill when setting up OAuth for local development and encountering redirect URI validation issues.
When not to use it
This skill may not be necessary for projects that do not require OAuth authentication or when developing in environments that do not use Portless.
What you can build with it
Setting Up Google OAuth
Use this skill to configure Google OAuth by registering a valid redirect URI that matches your portless domain.
Testing with Apple Sign In
Resolve issues with Apple Sign In by ensuring your local app uses a valid TLD that Apple accepts for OAuth.
Integrating Multiple Providers
Simplify the integration of various OAuth providers by using a consistent TLD across your local development team.
How to install OAuth with Portless
View source1. Install with the skills CLI
npx skills add vercel-labs/portless/oauth --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by vercel-labsOAuth with Portless
OAuth providers validate redirect URIs against domain rules. .localhost subdomains fail on most providers because they are not in the Public Suffix List or are explicitly blocked. Portless fixes this with --tld to serve apps on real, valid domains.
The Problem
When portless uses the default .localhost TLD, OAuth providers reject redirect URIs like http://myapp.localhost:1355/callback:
| Provider | localhost | .localhost subdomains | Reason |
|---|---|---|---|
| Allowed | Rejected | Not in their bundled PSL | |
| Apple | Rejected | Rejected | No localhost at all |
| Microsoft | Allowed | Allowed | Permissive localhost handling |
| Allowed | Varies | Must register each URI exactly | |
| GitHub | Allowed | Allowed | Permissive |
Google and Apple are the strictest. Microsoft and GitHub are more lenient with localhost.
The Fix
Use a valid TLD so the redirect URI passes provider validation:
portless proxy start --tld dev
portless myapp next dev
# -> https://myapp.dev
Any TLD in the Public Suffix List works: .dev, .app, .com, .io, etc.
Use a domain you own
Bare TLDs like .dev mean myapp.dev could collide with a real domain. Use a multi-segment TLD under a domain you control, so the app name stays clean and the domain structure lives in the TLD:
portless proxy start --tld local.yourcompany.dev
portless myapp next dev
# -> https://myapp.local.yourcompany.dev
This ensures no outbound traffic reaches something you don't own. For teams, set a wildcard DNS record (*.local.yourcompany.dev -> 127.0.0.1) so every developer gets resolution without /etc/hosts, and every developer shares the same redirect URIs in the provider console.
Provider Setup
- Go to Google Cloud Console > Credentials
- Create or edit an OAuth 2.0 Client ID (Web application)
- Add the portless domain to Authorized JavaScript origins:
https://myapp.dev - Add the callback to Authorized redirect URIs:
https://myapp.dev/api/auth/callback/google
Google validates domains against the Public Suffix List. The domain must end with a recognized TLD. .localhost subdomains fail this check; .dev, .app, .com, etc. all pass.
HTTPS is required for .dev and .app (HSTS-preloaded). Portless handles this automatically with --https.
Apple
Apple Sign In does not allow localhost or IP addresses at all.
- Go to Apple Developer > Certificates, Identifiers & Profiles
- Register a Services ID
- Configure Sign In with Apple, adding the portless domain as a Return URL:
https://myapp.dev/api/auth/callback/apple
The domain must be a real, publicly-resolvable domain name. Since portless maps the domain to 127.0.0.1 locally, the browser resolves it but Apple's server-side validation may require the domain to resolve publicly too. If Apple rejects the domain, add a public DNS A record pointing to 127.0.0.1 for your dev subdomain.
Microsoft (Entra / Azure AD)
- Go to Azure Portal > App registrations
- Create or edit an app registration
- Under Authentication, add a Web redirect URI:
https://myapp.dev/api/auth/callback/azure-ad
Microsoft allows http://localhost with any port for development. It also accepts .localhost subdomains in most cases. Using a custom TLD with portless is still recommended for consistency across providers.
Facebook (Meta)
- Go to Meta for Developers > App Dashboard
- Under Facebook Login > Settings, add the portless URL to Valid OAuth Redirect URIs:
https://myapp.dev/api/auth/callback/facebook
Facebook requires each redirect URI to be registered exactly (no wildcards). Strict Mode (enabled by default) enforces exact matching.
GitHub
- Go to GitHub Developer Settings > OAuth Apps
- Set Authorization callback URL:
https://myapp.dev/api/auth/callback/github
GitHub is permissive with localhost and subdomains. A custom TLD is not strictly required but keeps the setup consistent.
Auth Library Configuration
NextAuth / Auth.js
Set NEXTAUTH_URL to match the portless domain:
NEXTAUTH_URL=https://myapp.dev
NextAuth uses this to construct callback URLs. Without it, callbacks may use localhost and cause a mismatch.
Passport.js
Set the callbackURL in each strategy to use the portless domain:
new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.BASE_URL + "/auth/google/callback",
});
Set BASE_URL=https://myapp.dev in your environment.
Generic / Manual
Read the PORTLESS_URL environment variable that portless injects into the child process:
const baseUrl = process.env.PORTLESS_URL || "http://localhost:3000";
const callbackUrl = `${baseUrl}/auth/callback`;
Troubleshooting
"redirect_uri_mismatch" or "invalid redirect URI"
The redirect URI sent during the OAuth flow doesn't match what's registered with the provider. Check:
- The provider's registered redirect URI matches the portless domain exactly (protocol, host, path)
NEXTAUTH_URLor equivalent is set to the portless URL (notlocalhost)- The proxy is running with the correct TLD (
portless listto verify)
Provider requires HTTPS
.dev and .app TLDs are HSTS-preloaded, so browsers force HTTPS. Start the proxy:
portless proxy start --tld dev
Portless defaults to HTTPS on port 443 (auto-elevates with sudo). Run portless trust to add the local CA to your system trust store and eliminate browser warnings.
Apple rejects the domain
Apple may require the domain to resolve publicly. Add a DNS A record for your dev subdomain pointing to 127.0.0.1:
myapp.local.yourcompany.dev A 127.0.0.1
Or use a wildcard: *.local.yourcompany.dev A 127.0.0.1.
Callback goes to wrong URL after sign-in
The auth library is constructing the callback URL from localhost instead of the portless domain. Set the appropriate environment variable:
- NextAuth:
NEXTAUTH_URL=https://myapp.dev - Auth.js v5:
AUTH_URL=https://myapp.dev - Manual:
PORTLESS_URLis injected automatically; use it as the base URL
Example
See examples/google-oauth for a complete working example with Next.js + NextAuth + Google OAuth using --tld dev.
Frequently asked questions about OAuth with Portless
Similar skills
WinMD API Search
Easily find and explore Windows desktop APIs.
WebMCPify
Transform any web app into an agent-ready platform.
Phoenix Tracing
Instrument LLM applications with OpenInference tracing.
Foundry Hosted Agent CopilotKit
Guidance for developing agentic web apps on Azure.
Power Automate Foundation
Connect AI agents to Power Automate seamlessly.
Power Automate Flow Builder
Efficiently build and deploy Power Automate flows programmatically.
