Skip to content
Development
Skill

/oauth

Configure OAuth providers (Google, Apple, Microsoft, Facebook, GitHub, etc.) to work with portless local dev URLs. Use when setting up OAuth redirect URIs, fixing "redirect_uri_mismatch" or "invalid redirect" errors, configuring sign-in providers for local development, or when a

From plugin
portless
13k2 skills

Claude Code

$ npx -y skills add vercel-labs/portless --skill oauth --agent claude-code

SKILL.md

oauth.SKILL.md
name: oauth
description: Configure OAuth providers (Google, Apple, Microsoft, Facebook, GitHub, etc.) to work with portless local dev URLs. Use when setting up OAuth redirect URIs, fixing "redirect_uri_mismatch" or "invalid redirect" errors, configuring sign-in providers for local development, or when a provider rejects .localhost subdomains. Triggers include "OAuth not working with portless", "redirect URI mismatch", "Google/Apple/Microsoft sign-in fails locally", "configure OAuth for local dev", or any task involving OAuth callback URLs with portless domains.

OAuth 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 | | --------- | ----------- | ----------------------- | ------------------------------ | | Google | Allowed | Rejected | Not in their bundled PSL | | Apple | Rejected | Rejected | No localhost at all | | Microsoft | Allowed | Allowed | Permissive localhost handling | | Facebook | 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

Google

1. Go to [Google Cloud Console > Credentials](https://console.cloud.google.com/apis/credentials) 2. Create or edit an OAuth 2.0 Client ID (Web application) 3. Add the portless domain to **Authorized JavaScript origins**: `https://myapp.dev` 4. 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.

1. Go to [Apple Developer > Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources) 2. Register a Services ID 3. 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)

1. Go to [Azure Portal > App registrations](https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps) 2. Create or edit an app registration 3. 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)

1. Go to [Meta for Developers > App Dashboard](https://developers.facebook.com/apps/) 2. 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

1. Go to [GitHub Developer Settings > OAuth Apps](https://github.com/settings/developers) 2. 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"

Read more
@vercel-labs-2
Ships withportless

Replace port numbers with stable, named .localhost URLs for local development. For humans and agents. portless runs a local reverse proxy and gives each dev server a name.

Stars on GitHub

Momentum

stars in total
12.9k
Star history of vercel-labs/portless on GitHub, a chart by star-history.com

Other skills on portless.

portless

portless

Set up and use portless for named local dev server URLs (e.g. https://myapp.localhost instead of http://localhost:3000). Use when…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react4d252k
@facebook@facebookInstall Skill

Questions about oauth.

Which coding agents can use oauth?
oauth installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.