文章/2026 年 AdMob API OAuth 配置:scope 选择、refresh token 与 403 错误排查
工具评测

2026 年 AdMob API OAuth 配置:scope 选择、refresh token 与 403 错误排查

Google 文档没说清 AdMob API 到底用哪个 scope。这篇拆开 admob.readonly 和 admob.report 的差异、OAuth 客户端配置、refresh token 流程、还有 403 insufficient_scope 的排查路径。

2026年5月25日阅读时间: 9 分钟0 个主题标签
阅读过渡

上面是文章摘要,下面进入正文深读。可以配合目录逐段阅读,不会丢掉上下文。

工具评测6 个章节

上个 sprint 给我们 portfolio app 接 AdMob 收益 dashboard,又撞上同一堵 OAuth 墙。Google 的协议文档把通信格式讲得很细,但每个开发者第一个想问的问题它根本不答:到底用哪个 scope?reference 页列 endpoint,OAuth 页列 scope,两页之间没有任何连接。这篇就是我当初希望存在的那张连接图。

Google 文档没告诉你该用哪个 scope

打开 AdMob API 的 getting-started 页面,能看到两个 scope URL:admob.readonlyadmob.report。打开 REST reference,能看到 endpoint 树和字段 schema。但没有任何地方告诉你 accounts.list 该用 admob.readonlyaccounts.networkReport.generateadmob.report 才合理。没有 per-endpoint 的 scope 表。你只能挑一个 scope 试,让 403 错误教你映射。这就是 Google 在 2026 年实际交付的工作流,每个新接入者要为此付出半天调试时间。

admob.readonly vs admob.report:两个 scope 怎么选

admob.readonly admob.report
完整 scope URL https://www.googleapis.com/auth/admob.readonly https://www.googleapis.com/auth/admob.report
授予访问 "See all AdMob data. This may include account information, inventory and mediation settings, reports, and other data." "See ad performance and earnings reports. See publisher ID, timezone, and default currency code."
不授予 "This doesn't include sensitive data, such as payments or campaign details." Google 文档没写明确排除条款;按窄 scope 处理即可
适合场景 既要拉清单(apps、ad units、mediation groups)又要拉报表,一个凭证搞定 只做报表管道,希望 consent 屏幕权限最小化
来源 Google 文档 同上

实际上我做过的 dashboard 项目最后都申请 admob.readonly,因为只要 PM 多问一句"能不能也列出哪个 app 收益最高",你就需要 inventory 端点,单独 admob.report 给不了。窄 scope 只在确认服务真的就是 read-earnings-only、并且为外部上线在意 consent 屏幕观感时才值得。换句话说,admob.report 的卖点是把权限请求做轻,不是给你省钱也不是给你提速。

还有一点要说清楚:scope 是叠加关系不是层级关系。同一次 consent 流程里同时申请两个完全合法也很常见,返回的 access token 的 scope claim 会同时携带两个,用空格分隔。一起申请没有惩罚,唯一代价是 consent 屏幕多一个勾选框。生产环境我推荐固定要 admob.readonly,把 scope 列表写死成一个常量,避免后续不同接口因为 scope 不一致互相打架。

在 GCP 里配置 OAuth 客户端

在 Google Cloud Console 建项目,从 API Library 启用 AdMob API,进入 OAuth consent screen 配置页。如果不在 Google Workspace 组织内,选 External user type。把 https://www.googleapis.com/auth/admob.readonly(或只要 admob.report)加到 consent screen 的 scope 列表里。这一步最容易漏;scope 不在 consent screen 上,授权请求会静默降级,token 拿回来不带这个权限。

接着去 Credentials 创建 OAuth 2.0 Client ID。挑对 application type:有后端选 Web application,跑 CLI 工具选 Desktop app,loopback redirect 的脚本选 Installed app。Web application 客户端要把 authorized redirect URIs 一字不差地填进去。Google 文档直说:"the http or https scheme, case, and trailing slash ('/') must all match."。注册的是 https://app.example.com/oauth/callback,请求里写 https://app.example.com/oauth/callback/(多个斜杠)就会 redirect_uri_mismatch

下载 client JSON 或把 client ID/secret 写进密钥库。还要决定 consent screen 留在 Testing 还是推到 Production。单个内部用户用 Testing 没问题,但 Testing 模式下 refresh token 锁定 7 天过期,第 8 天 staging 一定会出事,半夜被 alarm 叫醒不止一次了。如果这套凭证要支撑长期服务端任务,上线前就要把 consent screen 走完审核推到 Production。验证流程一般要交隐私政策 URL、首页 URL,敏感 scope 还要录一段使用场景视频,预留两周时间比较稳。

国内开发者注意: AdMob 控制台和 GCP console 都需要稳定的 Google 网络。OAuth redirect_uri 不能用国内可访问的中转域名(Google 会做严格匹配),自建小 server 转发 code 是常见做法。

获取和刷新 token

初始授权请求里必须带上 access_type=offline,否则根本拿不到 refresh token。漏了的话 Google 只发一个 1 小时的 access token,第 61 分钟你的 job 就死了。Google 文档原话:设置 access_type=offline 会"instructs the Google authorization server to return a refresh token and an access token the first time that your application exchanges an authorization code for tokens"。

用户同意后,callback 收到 code。拿去 token endpoint 换:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your_client_id&
client_secret=your_client_secret&
redirect_uri=https%3A//your.app/oauth/callback&
grant_type=authorization_code

响应里有 access_tokenexpires_in(默认 3600 秒)、token_type: Bearerrefresh_token。立刻把 refresh token 存好。Google 警告过:"Note that the refresh token is only returned on the first authorization."。同一个用户和 client 再跑一次 consent,下一次响应里就没有 refresh_token 字段了,你会以为代码挂了。[community-verified] 的绕过办法是给授权 URL 加 prompt=consent,强制 Google 每次 consent 都重发 refresh token,省着点用。

刷新:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

client_id=your_client_id&
client_secret=your_client_secret&
refresh_token=1//0gC...stored_refresh_token&
grant_type=refresh_token

响应里给你新的 access token。Refresh token 本身一直有效到被 revoke,因此 server 端的常见做法是把 refresh token 加密存到数据库,access token 进内存缓存按 expires_in 设 TTL,到点重刷。不要把 access token 也持久化,那会让排查问题多绕一圈。

常见错误和排查

403 insufficient_scope:access token 不带端点要求的 scope。最常见原因是 consent screen 的 scope 列表里没你授权请求里写的那个,consent 静默颁发了一个窄 token。修:把 scope 加进 consent screen,用 prompt=consent 强制重跑 consent,重新颁发 refresh token。

400 invalid_grant:refresh token 不再被接受。AdMob 工作流里三大常见原因:(1) consent screen 还在 Testing,7 天过了;(2) refresh token 6 个月没用,Google 自动过期;(3) 用户改了 Google 密码且 token 带 Gmail scope,可能级联导致其他 token 失效。修:重跑 consent 流程拿新 refresh token;如果生产环境受影响,把 consent screen 推出 Testing。

403 PERMISSION_DENIED:用户鉴权通过了但根本没有任何 AdMob publisher 账号的访问权。修:去 admob.google.com 的 Settings > Account access 确认这个 Google 账号确实被邀请进了对应 AdMob 账号。新人常用个人 Gmail 接 consent,结果 publisher 在工作账号下。

Token 正常,但 accounts.list 返回空数组。 没有报错,就是 {}。根因:登录的用户挂在另一个 publisher 上,或者根本没有任何 publisher。修:打日志看 token 上的用户身份 claim,去 admob.google.com 核对那个用户名下到底有什么 publisher,再用正确账号重跑 consent。

速查:每个 endpoint 用哪个 scope

Google 没出 per-endpoint scope 映射,下表是我在生产环境跑通的版本。来源标签都标实话。

Endpoint 推荐 scope 来源
accounts.get (v1) admob.readonly [community-verified]
accounts.list (v1) admob.readonly [community-verified]
accounts.apps.list (v1) admob.readonly [community-verified]
accounts.adUnits.list (v1) admob.readonly [community-verified]
accounts.mediationReport.generate (v1) admob.report [community-verified]
accounts.networkReport.generate (v1) admob.report [community-verified]
accounts.adSources.list (v1beta) admob.readonly [community-verified]
accounts.adSources.adapters.list (v1beta) admob.readonly [community-verified]
accounts.adUnits.create (v1beta) 未知,Google 文档没指定写 scope [unverified]
accounts.adUnits.adUnitMappings.create (v1beta) 未知写 scope [unverified]
accounts.adUnitMappings.batchCreate (v1beta) 未知写 scope [unverified]
accounts.apps.create (v1beta) 未知写 scope [unverified]
accounts.campaignReport.generate (v1beta) admob.report [community-verified]
accounts.mediationGroups.list (v1beta) admob.readonly [community-verified]
accounts.mediationGroups.create / patch (v1beta) 未知写 scope [unverified]
accounts.mediationGroups.mediationAbExperiments.create / stop (v1beta) 未知写 scope [unverified]

任何 [unverified] 行如果你有官方来源能补,欢迎发到 xzf224@gmail.com,我会更新这张表。维护这种半官方半社区的映射表本质上是个长期任务,AdMob API 的 v1beta 接口集还在变化中,列表内容会随版本而更新。

分享文章

文章概览

读完前先看这几项

分类
工具评测
阅读时间
9 分钟
提到的工具
0
返回文章列表 →

下一步

读完后可以继续回到工具目录,对比具体产品。

去看工具