Portless 本地开发 OAuth 实战指南:用自定义 TLD 解决 redirect_uri_mismatch
【免费下载链接】portlessReplace port numbers with stable, named local URLs. For humans and agents.项目地址: https://gitcode.com/GitHub_Trending/por/portless
导读
本文讲解如何在 portless 本地开发环境中配置 OAuth 登录(Google、Apple、Microsoft、Facebook、GitHub 等),核心解决 "redirect_uri_mismatch"、"invalid redirect URI" 等常见报错。你会掌握:为什么.localhost子域名会被多数 OAuth 提供商拒绝、如何用portless proxy start --tld让本地应用跑在真实合法域名上、各提供商控制台的精确配置步骤,以及 NextAuth/Auth.js、Passport.js 等常见认证库的对接方式。读完即可在本地完整跑通 Google OAuth 登录。
问题根源:.localhost子域名无法通过 OAuth 校验
OAuth 提供商在登记回调地址时,会按照各自规则校验重定向 URI 的域名。portless 默认使用.localhost作为 TLD,生成的本地 URL 形如http://myapp.localhost:1355/callback。这类地址在多数提供商处会被直接拒绝:
| Provider | localhost | .localhost子域名 | 原因 |
|---|---|---|---|
| 允许 | 拒绝 | 不在其内置的 Public Suffix List(PSL)中 | |
| Apple | 拒绝 | 拒绝 | 完全不支持 localhost |
| Microsoft | 允许 | 允许 | 对 localhost 处理宽松 |
| 允许 | 视情况而定 | 必须精确注册每一个 URI | |
| GitHub | 允许 | 允许 | 宽松 |
其中 Google 与 Apple 最严格。Google 的 OAuth 凭据页面会用它内置的一份 Public Suffix List 校验回调域名,.localhost不在其中,因此myapp.localhost:3000会被报错:"must end with a public top-level domain (such as .com or .org)";纯localhost之所以可以,是因为 Google 把它硬编码进了白名单,但子域名不行。Apple Sign In 则干脆连localhost和 IP 地址都不允许。
解决方案:用--tld让应用跑在真实域名上
portless 支持用--tld指定任意合法 TLD 启动代理,让本地应用获得一个能通过提供商校验的域名:
portless proxy start --tld dev portless myapp next dev # -> https://myapp.devPublic Suffix List 中的任何 TLD 都可以:.dev、.app、.com、.io等。.dev是 Google 拥有的真实 gTLD,且被 HSTS 预加载(HSTS-preloaded),浏览器会强制 HTTPS——portless 默认开启 HTTPS 并自动处理证书,无需额外配置。
推荐:使用你拥有的多段域名
裸 TLD 意味着myapp.dev可能与别人拥有的真实域名撞车。更稳妥的做法是把域名结构放到 TLD 里,使用你控制下的多段 TLD:
portless proxy start --tld local.yourcompany.dev portless myapp next dev # -> https://myapp.local.yourcompany.dev这样能保证没有出站流量到达你不拥有的资源。对团队而言,设置一条通配 DNS 记录(*.local.yourcompany.dev -> 127.0.0.1),每个开发者在没有/etc/hosts的情况下也能解析,且所有开发者在提供商控制台共享同一组回调 URI。
portless 本身对多段 TLD 有原生支持:TLD 可以是dev.example.com这样的多段 DNS 名称,让本地 URL 镜像生产结构(myapp.dev.example.com),每个标签遵循 DNS 规则(小写字母、数字、内部连字符,每段最长 63 字符,总计 253 字符)。当配置了多个重叠 TLD(如example.com与dev.example.com)时,主机名会先匹配最长的 TLD,与配置顺序无关。
各提供商控制台配置
- 打开 Google Cloud Console > Credentials
- 创建或编辑一个 OAuth 2.0 Client ID(Web application)
- 在Authorized JavaScript origins中加入 portless 域名:
https://myapp.dev - 在Authorized redirect URIs中加入回调地址:
https://myapp.dev/api/auth/callback/google
Google 按 Public Suffix List 校验域名,域名必须以可识别的 TLD 结尾,.localhost子域名无法通过;.dev、.app、.com等都可以。注意.dev与.app因 HSTS 预加载强制要求 HTTPS,portless 用--https自动处理。
Apple
Apple Sign In 完全不允许localhost和 IP 地址。
- 打开 Apple Developer > Certificates, Identifiers & Profiles
- 注册一个 Services ID
- 配置 Sign In with Apple,把 portless 域名加入Return URL:
https://myapp.dev/api/auth/callback/apple
域名必须是真实、可公网解析的域名。由于 portless 在本地把域名映射到 127.0.0.1,浏览器可以解析,但 Apple 的服务端校验可能要求域名也能公开解析。如果 Apple 拒绝该域名,为开发子域名添加一条指向127.0.0.1的公网 DNS A 记录。
Microsoft(Entra / Azure AD)
- 打开 Azure Portal > App registrations
- 创建或编辑应用注册
- 在Authentication下添加Web重定向 URI:
https://myapp.dev/api/auth/callback/azure-ad
Microsoft 允许开发场景下的http://localhost(任意端口),多数情况下也接受.localhost子域名。但为了一致性,仍建议用 portless 的自定义 TLD 统一各提供商的配置。
Facebook(Meta)
- 打开 Meta for Developers > App Dashboard
- 在Facebook Login > Settings中,把 portless URL 加入Valid OAuth Redirect URIs:
https://myapp.dev/api/auth/callback/facebook
Facebook 要求每个重定向 URI 必须精确注册(不支持通配符),默认开启的 Strict Mode 强制精确匹配。
GitHub
- 打开 GitHub Developer Settings > OAuth Apps
- 设置Authorization callback URL:
https://myapp.dev/api/auth/callback/github
GitHub 对 localhost 和子域名都很宽松,自定义 TLD 并非必需,但可以让整套配置保持一致。
认证库配置
NextAuth / Auth.js
设置NEXTAUTH_URL与 portless 域名保持一致:
NEXTAUTH_URL=https://myapp.devNextAuth 用它来构造回调 URL;不设置的话回调可能落到localhost上导致不匹配。Auth.js v5 对应的环境变量是AUTH_URL=https://myapp.dev。
Passport.js
在每个策略里把callbackURL指向 portless 域名:
new GoogleStrategy({ clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, callbackURL: process.env.BASE_URL + "/auth/google/callback", });然后在环境中设置BASE_URL=https://myapp.dev。
通用 / 手动方案
读取 portless 注入到子进程的PORTLESS_URL环境变量(其实现位于 cli.ts,代码把PORTLESS_URL作为环境变量传给被代理的子进程,并使用配置的第一个 TLD):
const baseUrl = process.env.PORTLESS_URL || "http://localhost:3000"; const callbackUrl = `${baseUrl}/auth/callback`;疑难排查
"redirect_uri_mismatch" 或 "invalid redirect URI"
OAuth 流程中发出的重定向 URI 与提供商登记的不一致。逐项检查:
- 提供商登记的 URI 与 portless 域名完全一致(协议、主机、路径)
NEXTAUTH_URL或等价变量已设置为 portless URL(而不是localhost)- 代理以正确的 TLD 运行,用
portless list验证当前路由
提供商强制 HTTPS
.dev和.app是 HSTS 预加载域名,浏览器强制 HTTPS。启动代理:
portless proxy start --tld devportless 默认在 443 端口启用 HTTPS(必要时自动用 sudo 提权)。运行portless trust把本地 CA 加入系统信任库,消除浏览器证书警告。
Apple 拒绝域名
Apple 可能要求域名可公开解析。为开发子域名添加指向127.0.0.1的 DNS A 记录:
myapp.local.yourcompany.dev A 127.0.0.1或使用通配符:*.local.yourcompany.dev A 127.0.0.1。
登录后回调跳到错误 URL
认证库用localhost而不是 portless 域名构造回调 URL。设置对应环境变量:
- NextAuth:
NEXTAUTH_URL=https://myapp.dev - Auth.js v5:
AUTH_URL=https://myapp.dev - 手动方案:
PORTLESS_URL会被自动注入,直接用作 base URL
完整可运行示例
仓库中的 examples/google-oauth 是一个 Next.js + NextAuth + Google OAuth 的完整可运行示例,使用--tld dev。其package.json通过"portless": "google-oauth-example.portless"指定应用名,认证路由 只使用GOOGLE_CLIENT_ID与GOOGLE_CLIENT_SECRET两个环境变量注册 GoogleProvider,首页 提供 "Continue with Google" 登录按钮并实时展示当前域名、协议与 TLD。
按以下步骤运行:
npm install -g portless portless proxy start --tld dev创建 Google OAuth 客户端(Web application),填入 Authorized JavaScript originshttps://oauth-test.dev与 Authorized redirect URIshttps://oauth-test.dev/api/auth/callback/google,然后:
cd examples/google-oauth cp .env.example .env编辑.env:
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=your-client-secret NEXTAUTH_SECRET=generate-with-openssl-rand-base64-32 NEXTAUTH_URL=https://oauth-test.dev用openssl rand -base64 32生成NEXTAUTH_SECRET,最后安装依赖并启动:
pnpm install pnpm dev这会执行portless oauth-test next dev,把应用发布到https://oauth-test.dev。浏览器打开该地址点击 "Continue with Google" 即可验证完整登录流程。
如果只想用 Google OAuth 且不愿更换 TLD,也可以额外注册http://localhost:3000/api/auth/callback/google作为回调 URI(Google 允许带任意端口的纯localhost),并设置NEXTAUTH_URL=http://localhost:3000——代价是 OAuth 回调流程失去 portless 的命名 URL、无端口冲突等收益。
小结
OAuth 提供商对.localhost子域名的拒绝是本地开发对接第三方登录时最常见的拦路虎。portless 通过--tld把本地应用映射到真实合法域名,既绕过了 PSL 校验,又保留了命名 URL 的全部开发体验。对团队场景,配合自持域名与通配 DNS,还能实现所有开发者共享同一组回调 URI 与配置。结合本仓库的 OAuth 技能文档 与 google-oauth 示例,即可在几分钟内让本地 OAuth 登录跑通。
【免费下载链接】portlessReplace port numbers with stable, named local URLs. For humans and agents.项目地址: https://gitcode.com/GitHub_Trending/por/portless
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考