Android OAuth2 出现 redirect_uri_mismatch 如何解决?
结论
出现 redirect_uri_mismatch,说明 OAuth 请求中的 redirect_uri 没有与 Android 的 Intent Filter、Google Cloud 中 OAuth 客户端的类型或身份信息正确对应。
此场景应使用 Android OAuth 客户端,并确保运行时的 applicationId、调试证书的 SHA-1 指纹和自定义 URI scheme 配置一致。回调地址可以写成:
net.openid.appauthdemo:/oauth2redirect
对应的 Intent Filter 声明 scheme 和 path 即可:
<data
android:scheme="net.openid.appauthdemo"
android:path="/oauth2redirect" />
原配置错在哪里
下面的地址缺少 :,不是合法的自定义 scheme 回调地址:
net.openid.appauthdemo/oauth2redirect
原 Manifest 中的配置是:
<data
android:scheme="net.openid.appauthdemo"
android:host="oauth2redirect" />
它实际匹配的是:
net.openid.appauthdemo://oauth2redirect
这两种 URI 的结构不同:
net.openid.appauthdemo:/oauth2redirect
↑ 单斜杠,无 host
net.openid.appauthdemo://oauth2redirect
↑ 双斜杠,oauth2redirect 是 host
OAuth 提供方通常会精确匹配 redirect_uri。scheme、斜杠数量、host、path 或大小写只要有一处不同,就可能触发 redirect_uri_mismatch。
原来的 HTTPS 地址也有问题:
https://appauth.demo-app.io/oauth2redirect
该域名不属于当前应用。使用 HTTPS App Link,需要控制对应域名,并完成服务端回调登记和 Android 域名关联。只在 Manifest 中声明别人的域名,无法把它变成当前应用的 OAuth 回调地址。
配置 auth_config.json
可以使用以下配置:
{
"client_id": "<Android OAuth client ID>",
"redirect_uri": "net.openid.appauthdemo:/oauth2redirect",
"end_session_redirect_uri": "net.openid.appauthdemo:/oauth2redirect",
"authorization_scope": "openid email profile",
"authorization_endpoint_uri": "https://accounts.google.com/o/oauth2/v2/auth"
}
client_id 要使用当前 Android 应用对应的 OAuth Client ID。不要因为需要填写 Web redirect URI,就换成 Web application 类型的 Client ID。
JSON 语法也要正确。问题中的这一行缺少开头引号:
"end_session_redirect_uri":net.openid.appauthdemo/oauth2redirect"
至少要改成合法的 JSON 字符串:
"end_session_redirect_uri": "net.openid.appauthdemo:/oauth2redirect"
end_session_redirect_uri、撤销令牌和退出登录属于其他流程,无法解决授权阶段的 redirect_uri_mismatch。相关 endpoint 是否受 Google 当前配置支持,需要单独核对。
配置 AndroidManifest.xml
<activity
android:name="net.openid.appauth.RedirectUriReceiverActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="net.openid.appauthdemo"
android:path="/oauth2redirect" />
</intent-filter>
</activity>
这里不需要 android:host,因为回调地址的结构是:
scheme:/path
scheme://host/path 是另一种 URI 结构:
scheme://host/path
Android Studio 可能会提示 Intent Filter 没有 host,但这不表示该 URI 结构无法编译或匹配。是否有效,应以实际的 URI 结构和运行结果为准。
Gradle 中只填写 scheme
如果项目使用 AppAuth 提供的 Manifest placeholder,它的值只能是 scheme:
android {
namespace 'net.openid.appauthdemo'
defaultConfig {
applicationId 'net.openid.appauthdemo'
manifestPlaceholders = [
appAuthRedirectScheme: 'net.openid.appauthdemo'
]
}
}
下面这种写法不正确:
appAuthRedirectScheme: 'https://appauth.demo-app.io/oauth2redirect'
appAuthRedirectScheme 不是完整 URI,应填写 net.openid.appauthdemo 这样的 scheme。
如果已经手动声明了 RedirectUriReceiverActivity,还要检查合并后的 Manifest,确认 placeholder 生成的 Intent Filter 没有与手写配置重复或冲突。
Google Cloud 中填写哪些信息
Android OAuth 客户端通常通过以下信息识别应用:
- Package name,也就是最终安装 APK 的
applicationId - 签名证书的 SHA-1 fingerprint
namespace 和 applicationId 很容易混淆:
namespace 'net.openid.appauthdemo'
applicationId 'net.openid.appauthdemo'
两者可以相同,含义却不一样。Google Cloud 中 Android credential 的 Package name 应与最终构建变体的 applicationId 对应。如果项目使用了 applicationIdSuffix,debug 包的实际 ID 也可能随之变化。
Android credential 页面没有普通 Web 客户端那样的任意 redirect URI 输入框,这是正常的。通过 AppAuth 使用自定义 scheme 时,如果控制台为该 Android credential 提供了 Enable custom URI scheme 选项,需要将其启用。
不要为了获得 redirect URI 输入框而创建 Web client,再把 Web client ID 直接用于 Android AppAuth 流程。客户端类型不一致同样会导致校验失败。
SHA-1 和 SHA-256 怎么选
Google Cloud 要求 SHA-1 时,应填写 keytool 输出中的这一项:
SHA1: 7B:86:D1:7B:EA:41:22:3A:60:D2:F6:72:B0:7A:57:FA:56:1F:8E:8F
下面这行表示证书使用的签名算法:
Signature algorithm name: SHA256withRSA
它不表示控制台应填写 SHA-256 fingerprint。
还要确认应用确实由该 debug.keystore 签名。换电脑、切换用户目录或重新生成 debug keystore,都可能改变 SHA-1。可以通过 Gradle 的签名报告查看实际构建使用的证书:
./gradlew signingReport
Windows 下通常可以运行:
gradlew signingReport
修改后如何验证
配置修改后,可以按以下顺序测试:
- 确认 Google Cloud 中 Android credential 的 Package name 与当前构建变体的
applicationId相同。 - 确认 SHA-1 来自实际签名该 APK 的 keystore。
- 确认
auth_config.json使用了对应的 Android Client ID。 - 确认授权请求实际发送的
redirect_uri是net.openid.appauthdemo:/oauth2redirect。 - 检查合并后的 Manifest,确认 Receiver 的 scheme 和 path 与该 URI 完全一致。
- 重新构建 APK,卸载旧应用后再安装。必要时先清除应用数据和浏览器中的旧授权状态。
资源文件和 Manifest 会被打包进 APK。清除应用数据不会让旧 APK 使用新的配置。开发期间频繁调整 OAuth 配置时,卸载后重新安装通常更可靠。
公开这些信息有什么风险
OAuth Client ID、Android package name,以及证书的 SHA-1 或 SHA-256 fingerprint 通常是公开标识,不属于密码或私钥。别人仅凭这些信息无法生成你的签名 APK,也不能直接登录你的 Google 账号。
以下内容不应公开:
- OAuth client secret
- access token、refresh token 或 authorization code
- Google 账号密码和恢复代码
- API key,尤其是没有调用范围和应用限制的 key
- keystore 文件、私钥及其密码
- 包含个人邮箱、姓名、项目成员、账单信息或内部项目标识的截图
未遮盖的账号信息仍可能造成隐私泄露,并被用于定向钓鱼或社工攻击。公开内容中的个人资料应删除或遮盖,同时检查 Google Cloud 项目的凭据、OAuth 授权、API key 限制和异常调用记录。测试项目不再使用时,可以删除或停用相关 OAuth credential。如果已经公开过 token、client secret、API key 或 keystore,应立即撤销或轮换。
备注:内容仅供参考。
