oauth

작성자: vercel

OAuth 제공자(Google, Apple, Microsoft, Facebook, GitHub 등)를 포트리스 로컬 개발 URL과 함께 작동하도록 구성합니다. OAuth 리디렉션 URI를 설정할 때 사용합니다.

npx skills add https://github.com/vercel-labs/portless --skill oauth

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:

Providerlocalhost.localhost subdomainsReason
GoogleAllowedRejectedNot in their bundled PSL
AppleRejectedRejectedNo localhost at all
MicrosoftAllowedAllowedPermissive localhost handling
FacebookAllowedVariesMust register each URI exactly
GitHubAllowedAllowedPermissive

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
  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
  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
  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
  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
  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"

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:

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 for a complete working example with Next.js + NextAuth + Google OAuth using --tld dev.

vercel의 다른 스킬

vercel
vercel
로컬 개발 및 테스트를 위한 Vercel REST API 에뮬레이션입니다. 사용자가 로컬에서 Vercel API 엔드포인트와 상호작용하거나 Vercel 통합을 테스트해야 할 때 사용합니다.
cron-jobs
vercel
Vercel Cron Jobs 구성 및 모범 사례. vercel.json에서 예약된 작업을 추가, 편집 또는 디버깅할 때 사용합니다.
codegen
vercel
json-render을 위한 코드 생성 유틸리티입니다. UI 명세서에서 코드를 생성하거나, 사용자 정의 코드 내보내기를 구축하거나, 명세서를 탐색하거나, props를 직렬화할 때 사용합니다.
next-best-practice
vercel
Next.js 모범 사례 - 파일 규칙, RSC 경계, 데이터 패턴, 비동기 API, 메타데이터, 오류 처리, 라우트 핸들러, 이미지/폰트 최적화,…
benchmark-sandbox
vercel
Vercel Sandbox에서 vercel-plugin eval 시나리오를 로컬 WezTerm 패널 대신 실행합니다. Claude Code와 플러그인이 사전 설치된 임시 마이크로VM을 프로비저닝합니다.
write-guide
vercel
점진적인 예제를 통해 실제 사용 사례를 가르치는 기술 가이드를 제작합니다. 개념은 독자가 필요로 할 때만 소개됩니다.
benchmark-testing
vercel
벤치마크 테스트 프로젝트를 생성하고 실행하여 실제 시나리오에서 vercel-plugin 스킬 인젝션을 테스트합니다. 격리된 디렉토리를 설정하고, 설치하며…
ai-gateway
vercel
Vercel AI Gateway 전문가 안내. 모델 라우팅, 제공업체 장애 조치, 비용 추적 또는 통합된 방식을 통해 여러 AI 제공업체를 관리할 때 사용합니다.