firebase / firebase/firebase-admin-go
VerifyIDToken fails with INVALID_ARGUMENT: failed to verify token signature for valid Firebase ID token
- Dominant language
- Go
- Stars
- 1.3k
- Forks
- 274
- Avg merge
- 10h 39m
- Merged PRs (30d)
- 2
Description
## Description
When verifying a Firebase ID token generated by a Flutter Firebase Auth SDK, the Go Admin SDK consistently returns:
`InvalidArgument desc = failed to verify token signature`
Even though:
- The token header contains a valid `kid` present in the keys fetched from
`https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com`
- The `iss` and `aud` in the payload match the Firebase project (`demo-project-123456`)
- The token has a valid `iat`/`exp` and is not expired
- The Admin SDK is initialized with the correct service account and `ProjectID`
- System clock is correct
- No emulator is used (`FIREBASE_AUTH_EMULATOR_HOST` unset)
---
## Environment
- **SDK**: `firebase.google.com/go/v4`
- **Go version**: `go1.25`
- **OS/Env**: (windows)
- **Project ID**: `demo-project-123456`
## Steps to reproduce
1. Sign in to Firebase Auth from a Flutter mobile client using Google provider:
```dart
final user = await FirebaseAuth.instance.signInWithCredential(credential);
final token = await user.user?.getIdToken();
```
2. Send the idToken to the backend.
3. On the backend, verify with Go Admin SDK:
```go
package main
import (
"context"
"fmt"
"log"
firebase "firebase.google.com/go/v4"
"google.golang.org/api/option"
)
func main() {
ctx := context.Background()
app, err := firebase.NewApp(ctx, &firebase.Config{ProjectID: "demo-project-123456"},
option.WithCredentialsFile("service-account.json"))
if err != nil {
log.Fatal(err)
}
auth, err := app.Auth(ctx)
if err != nil {
log.Fatal(err)
}
token := ""
t, err := auth.VerifyIDToken(ctx, token)
if err != nil {
log.Fatalf("verify failed: %v", err)
}
fmt.Println("UID:", t.UID)
}
```
4. Observe error:
`failed to verify token signature`
## Sample Token
### Header
```json
{
"alg": "RS256",
"kid": "e3ee7e028e3885a345ce07055f846862255a7046",
"typ": "JWT"
}
```
### Payload
```json
{
"name": "Mr Robot",
"picture": "https://lh3.googl....",
"iss": "https://securetoken.google.com/demo-project-123456",
"aud": "demo-project-123456",
"auth_time": 1757591071,
"user_id": "demoUser12345",
"sub": "demoUser12345",
"iat": 1757591071,
"exp": 1757594671,
"email": "mrRobot@gmail.com",
"email_verified": true,
"firebase": {
"identities": {
"google.com": [
"123456789..."
],
"email": [
"mrRobot@gmail.com"
]
},
"sign_in_provider": "google.com"
}
}
```
### Expected behavior
`VerifyIDToken` should successfully verify and return a parsed auth.Token struct with UID/email claims.
### Actual behavior
Verification fails with: "INVALID_ARGUMENT" "failed to verify token signature"
## Additional notes
- We validated the token manually: base64-decoding header/payload shows correct structure.
- The kid matches one of the keys in Google’s x509 JWKS endpoint.
- No emulator is used, and project IDs match.
- Same error reproduces in a minimal standalone program outside of our service.
and the execution hit
auth/token_verifier.go: 310
```go
func (tv *tokenVerifier) verifySignatureWithKeys(ctx context.Context, token string, keys []*publicKey) bool {
segments := strings.Split(token, ".")
var h jwtHeader
decode(segments[0], &h)
verified := false
for _, k := range keys {
if h.KeyID == "" || h.KeyID == k.Kid {
if verifyJWTSignature(segments, k) == nil {
verified = true
break
}
}
}
return verified
}
```
Contributor guide
Assessment
This issue has not been assessed yet.