I was having this same issue. Validation was taking anywhere from 200-400ms. That was something like 60-95% of the total request time for the service in general. This was using the Python SDK, but I imagine it's the same for every SDK.
The way I found to fix this was to manually validate the payload using Google's Certificates. Instructions can be found here: https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library
A sample implementation in Python here:
from jose import jwt
...
def verify_token(token: str) -> dict[str, Any]:
"""
Verifies the JWT Token without having to make a network request to Firebase.
Args:
token: The JWT Token to validate
"""
alg = "RS256"
headers = jwt.get_unverified_header(token)
key_id = headers["kid"]
if key_id not in settings.FIREBASE_CERTIFICATES.keys():
raise Exception(f"Unknown key id: {key_id}")
key = settings.FIREBASE_CERTIFICATES[key_id]
decoded = jwt.decode(token, key, algorithms=[alg], audience=settings["FIREBASE_AUDIENCE"])
current_ts = int(dt.datetime.now().timestamp())
if decoded.get("exp", 0) < current_ts:
raise Exception("Token expired")
if decoded.get("iat", 0) > current_ts:
raise Exception("Token issued in the future")
if decoded.get("aud", "") != settings["FIREBASE_AUDIENCE"]:
raise Exception("Invalid audience")
if decoded.get("iss", "") != settings["FIREBASE_ISSUER"]:
raise Exception("Invalid issuer")
if not decoded.get("sub", ""):
raise Exception("Invalid subject")
if decoded.get("auth_time", 0) > current_ts:
raise Exception("Invalid auth time")
return {
"uid": decoded.get("user_id", ""),
"email": decoded.get("email", ""),
"email_verified": decoded.get("email_verified", False),
"phone_number": decoded.get("phone_number", ""),
}
This uses a settings.FIREBASE_CERTIFICATES
which as an object (Python's dict in this case) that holds the KeyID:Certificate pair. It also needs settings.FIREBASE_AUDIENCE
which is the Project ID. The FIREBASE_ISSUER
is just https://securetoken.google.com/<projectId>
.
With that I had response times going from 500ms to 15ms. Insane.
The downside is that if you're using the object that the validation method returns, this won't get you all the relevant information. For my use case specifically the JWT returns everything I needed, so no extra requests were needed.