Skip to content

VerifyIDToken fails with INVALID_ARGUMENT: failed to verify token signature for valid Firebase ID token #715

Description

@harpy-wings

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:

    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 := "<PASTE_ID_TOKEN_HERE>"
    t, err := auth.VerifyIDToken(ctx, token)
    if err != nil {
        log.Fatalf("verify failed: %v", err)
    }
    fmt.Println("UID:", t.UID)
}
  1. Observe error:
    failed to verify token signature

Sample Token

Header

{
  "alg": "RS256",
  "kid": "e3ee7e028e3885a345ce07055f846862255a7046",
  "typ": "JWT"
}

Payload

{
  "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

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
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions