Android Studio调用FCM发送推送报401 AuthFailureError问题
FCM跨设备推送报AuthFailureError(401错误)原因与修复方案
你遇到的com.android.volley.AuthFailureError伴随接口返回401状态码,本质是调用FCM推送接口时未通过服务端鉴权,以下是具体诱因和对应解决方式:
核心产生原因
- 请求头格式不规范:代码中鉴权头的键名写为全小写
authorization,FCM接口对头字段大小写敏感,小写的鉴权头会被判定为未携带合法鉴权信息;同理Content-type写法也不符合HTTP标准头规范。 - 服务端密钥配置错误:代码中引用的
fcmServerKey不是合法的FCM Legacy服务端密钥,属于最高发的诱因,常见错误场景包括:- 误用客户端Web API Key:也就是
google-services.json文件里的current_key字段,该密钥仅开放给客户端使用,没有推送发送权限 - 误复制Firebase项目的APP ID、客户端SDK配置值等非服务端密钥
- 复制密钥时夹带了多余的空格、换行符
- 密钥已在Firebase控制台被重置,旧密钥自动失效
- 误用客户端Web API Key:也就是
- 接口与鉴权方式不匹配:代码中调用的是FCM Legacy版发送接口,如果误用了FCM V1版本的鉴权规则(V1需要OAuth2.0短期令牌,不支持
key=xxx的拼接格式),也会直接返回401。 - 服务权限未开通:Firebase项目的Cloud Messaging API处于未启用状态,对应密钥没有推送发送权限。
修复步骤
- 修正请求头写法,将头字段调整为HTTP标准大小写格式,鉴权头键名改为
Authorization,内容类型头改为Content-Type。 - 核对正确的Legacy服务端密钥:
- 打开对应Firebase项目的设置页面
- 切换到「云消息传递」标签页
- 在「Cloud Messaging API (Legacy)」板块,确认服务状态为已启用,再复制板块内显示的服务器密钥替换代码中的
fcmServerKey,不要使用其他位置的密钥值。
- 如果已经迁移到FCM V1版本接口,不要继续使用Legacy的
key=xxx鉴权方式,要么换回Legacy接口地址匹配Legacy密钥,要么按照V1规范生成OAuth2.0访问令牌做鉴权。 - 安全风险修复:不要在安卓客户端代码里硬编码FCM服务端密钥、直接从客户端调用FCM发送接口,客户端代码很容易被反编译导致密钥泄露,恶意人员拿到密钥可以向你的所有应用用户推送垃圾消息。正确实现逻辑是把推送发送逻辑部署到你自己的业务服务端,客户端只负责把设备推送Token上报给你的服务端,由服务端调用FCM接口完成推送下发。
修正后的参考代码
public static void SendNotifications(Context applicationContext, String targetToken, String title, String body) { // 注意:客户端直接调用FCM发送接口存在严重密钥泄露风险,仅做临时调试使用 StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); RequestQueue queue = Volley.newRequestQueue(applicationContext); try { JSONObject json = new JSONObject(); json.put("to", targetToken); JSONObject notification = new JSONObject(); notification.put("title", title); notification.put("body", body); json.put("notification", notification); // Legacy版FCM发送接口地址 String postUrl = "https://fcm.googleapis.com/fcm/send"; JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, postUrl, json, response -> Log.e("Result", String.valueOf(response)), error -> Log.e("Result", String.valueOf(error)) ) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> header = new HashMap<>(); // 修正头字段为标准格式 header.put("Content-Type", "application/json"); header.put("Authorization", "key=" + fcmServerKey); return header; } }; queue.add(jsonObjectRequest); } catch (JSONException jsonException) { jsonException.printStackTrace(); } }
调试技巧:如果修正代码后依然返回401,可以先把密钥和请求参数放到接口调试工具中直接调用FCM接口测试,如果工具请求也返回401,说明问题和代码逻辑无关,直接排查密钥有效性和项目服务开通状态即可。
内容的提问来源于stack exchange,提问作者XDfox
相关产品推荐
相关产品推荐

