Skip to main content
skill Claude Code CX Codex Cursor GitHub Copilot

oauth — Claude Code skill: what it does, how to install

Configures OAuth providers to work with portless local development domains and resolves redirect URI mismatches.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add vercel-labs/portless --skill oauth -a claude-code
Open on GitHub

What oauth does

OAuth providers validate redirect URIs against strict domain rules. Apple blocks localhost entirely. Google rejects .localhost subdomains because they are missing from its Public Suffix List. This skill guides your agent to run portless with valid custom TLDs via --tld so provider validation passes.

The reference includes setup steps for Google, Apple Developer, Azure AD, Meta, and GitHub. It provides configuration patterns for NextAuth, Auth.js, and Passport.js using PORTLESS_URL and NEXTAUTH_URL. Apple requires public resolution, so you must add an A record pointing to 127.0.0.1 before Sign In with Apple will work.

What it helps with

  • fix redirect_uri_mismatch errors during local OAuth development
  • configure Apple Sign In callback URLs without a live production host
  • set up Google OAuth client credentials for custom dev domains
  • connect NextAuth and Passport.js to portless subdomains

Example prompts for the agent

  • Fix redirect_uri_mismatch when signing in with Google on portless
  • Configure Apple Sign In callback for my local portless domain
  • Set up NextAuth environment variables with portless

How to install oauth

1Skills CLI (Vercel)

npx skills add vercel-labs/portless --skill oauth -a claude-code

2Manually: put the files in place

~/.claude/skills/oauth/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/oauth/

From the same set2

The whole set →

Similar

python-configuration Seth Hobson This skill moves Python settings into environment variables and validates typed configuration. Use it for secrets and environment-specific behavior. Claude Code CX Codex Cursor 11,508installs developing-genkit-python official google A skill for building Genkit apps in Python: generation, streaming, tools, flows and agents. Useful when your agent fumbles imports or Genkit API calls. Claude Code Gemini CLI CX Codex 3,600installs developing-genkit-js official google This skill helps build and troubleshoot Genkit AI apps in Node.js and TypeScript. Use it for flows, agents, tools, and Genkit API errors. Claude Code Gemini CLI CX Codex 3,600installs billing-automation Seth Hobson This skill helps build subscription billing, invoicing, and failed-payment recovery. Use it for SaaS products and services with recurring charges. Claude Code CX Codex Cursor 11,245installs python-background-jobs Seth Hobson This skill shows how to move long-running Python work out of request handling and into workers. Use it for queues, exports, notifications, and event-driven flows. Claude Code CX Codex Cursor 11,137installs flowstudio-power-automate-mcp official github Connects GitHub Copilot to Power Automate through FlowStudio MCP, with auth setup, tool discovery, and oversized-response handling. GitHub Copilot 4,200installs mcp-builder official anthropics This skill walks through building an MCP server in TypeScript or Python, from reading the protocol spec to writing tests and evaluation questions. Claude Code Claude.ai 130,949installs google-agents-cli-adk-code official Google A reference skill for building ADK agents with tools, callbacks, state, and workflows. Use it when an agent project needs concrete API patterns or code examples. Claude Code CX Codex Cursor +1 511,400installs

Questions about oauth

How do I install oauth in Claude Code?

Run npx skills add vercel-labs/portless --skill oauth -a claude-code in your terminal.

What does the oauth skill do?

It provides setup guides to configure OAuth callbacks across providers when using portless local development domains.

Why does Apple Sign In fail with portless localhost?

Apple rejects localhost domains outright and checks DNS publicly. You need a custom TLD with a public DNS A record pointing to 127.0.0.1.

Source text

SKILL.md · Apache-2.0
---
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:

```bash
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:

```bash
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:

```env
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:

```js
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:

```js
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:

1. The provider's registered redirect URI matches the portless domain exactly (protocol, host, path)
2. `NEXTAUTH_URL` or equivalent is set to the portless URL (not `localhost`)
3. The proxy is running with the correct TLD (`portless list` to verify)

### Provider requires HTTPS

`.dev` and `.app` TLDs are HSTS-preloaded, so browsers force HTTPS. Start the proxy:

```bash
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_URL` is injected automatically; use it as the base URL

## Example

See [`examples/google-oauth`](../../examples/google-oauth) for a complete working example with Next.js + NextAuth + Google OAuth using `--tld dev`.

© vercel-labs · Apache-2.0 · vercel-labs/portless

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor