firebase / firebase/firebase-admin-node
Misleading error message for THIRD_PARTY_AUTH_ERROR: raw "OAuth 2 access token" text surfaced instead of the APNs-specific message
- Lenguaje dominante
- TypeScript
- Estrellas
- 1.7k
- Forks
- 419
- Merge medio
- 3 d 10 h
- PR fusionados (30 d)
- 16
Descripción
## Summary
When FCM rejects an iOS send with `UNAUTHENTICATED`, the SDK surfaces the raw
gateway message ("...Expected OAuth 2 access token...") instead of its own
APNs-specific message, even though the error is classified as
`messaging/third-party-auth-error`. This sends developers down the wrong path
(debugging their own service-account / OAuth setup) when the real cause is a
downstream APNs credential problem.
## What happened
Sending to iOS device tokens, some tokens fail with:
```json
HTTP 401
{
"error": {
"code": 401,
"status": "UNAUTHENTICATED",
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. ...",
"details": [{ "@type": "...FcmError", "errorCode": "THIRD_PARTY_AUTH_ERROR" }]
}
}
```
`error.code` is correctly `messaging/third-party-auth-error`, but `error.message`
is the raw *"Expected OAuth 2 access token"* text. That message strongly implies
a problem with the caller's own authentication (service account / access token),
so it's natural to spend several debugging cycles verifying OAuth, the service
account, token refresh, etc. — all of which are fine. The actual cause is on the
APNs side (e.g. an APNs auth key/certificate that doesn't cover the environment a
given token was minted in). The misleading message cost us multiple debugging
rounds before we inspected `details[].errorCode`.
## Root cause in the SDK
In `src/messaging/error.ts` on current `main`:
- `UNAUTHENTICATED` is mapped to `THIRD_PARTY_AUTH_ERROR` (line ~201), and there is
a clear canonical message for it (lines ~133–137):
> "A message targeted to an iOS device could not be sent because the required
> APNs SSL certificate was not uploaded or has expired. Check the validity of
> your development and production certificates."
- But the error message is assigned as (line ~260):
```ts
error.message = message || error.message;
```
Since the raw server `message` is truthy, it always wins, so the SDK's own
clearer, APNs-specific message is never shown for this code — the misleading
"OAuth 2 access token" text is surfaced instead.
## A second, smaller issue: the canonical message is dated
Even when shown, the canonical message only mentions an *"APNs SSL certificate"*
and *"development and production certificates"* — i.e. the `.p12` model. Modern
setups use `.p8` **APNs auth keys** (token-based auth), and Web Push uses VAPID
keys. For those, "certificate ... has expired / check your certificates" is
itself misleading, because there is no certificate involved.
## Suggested fix
1. For `third-party-auth-error`, prefer (or prepend) the SDK's canonical message
rather than the raw `UNAUTHENTICATED` gateway text, since that raw text
systematically points debugging in the wrong direction. The raw text can be
kept as "Raw server response: ..." (the SDK already appends that in some
paths).
2. Update the canonical message to cover APNs **auth keys (`.p8`)** and **Web Push
(VAPID)**, not just SSL certificates.
## Environment
- Verified against current `main`, `src/messaging/error.ts`.
- Reproduced on a real send to an affected iOS token (401 / UNAUTHENTICATED /
`details[].errorCode = THIRD_PARTY_AUTH_ERROR`).
Happy to open a PR along the lines of the suggested fix if this direction sounds right.
Guía de contribución
Línea de trabajo
Empieza en src/messaging/error.ts leyendo el mapeo de THIRD_PARTY_AUTH_ERROR y la asignación posterior de error.message. Confirma cómo se selecciona el mensaje canónico de APNs cuando está presente la respuesta UNAUTHENTICATED sin procesar y, después, actualiza el comportamiento y la redacción para que se contemplen las claves de autenticación de APNs y las credenciales VAPID de Web Push. La tarea está terminada cuando third-party-auth-error ya no muestra la guía sin procesar y engañosa de OAuth como su mensaje principal.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- typescript
- Área
- api, backend
- Tipo de issue
- Error
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Estado de actividad
- Tranquilo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 70/100