Android携带OAuth idToken调用Google App Script更新表格返回401如何解决
问题根因
你的配置有三个核心错误:
- 你获取的是ID Token,不是Google API调用需要的Access Token,ID Token仅用于后端验证用户身份,无法用于Google Apps Script(下称GAS)的身份校验
- 授权头格式错误,GAS要求OAuth2授权头必须是
Bearer <Access Token>的格式,你直接把Token塞到Authorization头里不符合规则,额外加的多余请求头也可能干扰校验 - 你强行设置了
Content-Type: application/json,但你的参数是通过表单格式提交的,格式不匹配会导致GAS无法正常读取请求参数,也可能触发权限校验失败
分步修改方案
1. 调整授权逻辑,获取正确的Access Token
你现在用account.getIdToken()拿到的是ID Token,需要替换为Access Token:
- 首先精简不必要的Scope,只保留表格操作需要的权限即可,多余的权限反而可能触发谷歌的安全校验:
@NonNull private GoogleSignInOptions getGoogleSignOptions() { return new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) // 不需要请求ID Token .requestScopes(new Scope("https://www.googleapis.com/auth/spreadsheets")) .build(); }
- 登录成功后通过
GoogleAuthUtil获取Access Token,注意不能在主线程执行该操作:
private void handleSignInResult(Task<GoogleSignInAccount> completedTask) { try { GoogleSignInAccount account = completedTask.getResult(ApiException.class); new Thread(() -> { try { String scope = "oauth2:" + "https://www.googleapis.com/auth/spreadsheets"; oAuthAccessToken = GoogleAuthUtil.getToken(MainActivity.this, account.getAccount(), scope); runOnUiThread(() -> Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show()); } catch (Exception e) { e.printStackTrace(); } }).start(); } catch (ApiException e) { Log.w(TAG, "signInResult:failed code=" + e.getStatusCode()); } }
记得在AndroidManifest.xml里添加网络权限和GET_ACCOUNTS权限。
2. 修正Volley请求配置
删掉多余的请求头,只保留正确的授权头,不要强行修改Content-Type,Volley的StringRequest默认表单格式刚好匹配GAS的参数读取规则:
@Override public Map<String, String> getHeaders() throws AuthFailureError { HashMap<String, String> headers = new HashMap<>(); headers.put("Authorization", "Bearer " + oAuthAccessToken); return headers; }
3. 确认GAS Web App的部署配置
每次修改GAS代码后都要重新发布新版本,不要用测试部署的URL,正式部署时请按以下配置设置:
- 执行身份:
我(你的邮箱)或者访问网络应用的用户(如果需要用访问者身份修改表格选后者) - 谁可以访问:
任何人或者拥有Google账号的任何人(根据你的业务需求选择)
补充验证
你可以把Android端打印出的oAuthAccessToken复制到Postman里,用Bearer授权格式发起请求,就能复现Android端的请求结果,快速定位问题。
内容的提问来源于stack exchange,提问作者Taco Man
相关产品推荐
相关产品推荐

