Token used too early error thrown by firebase_admin auth's verify_id_token method
Asked Answered
C

4

11

Whenever I run

from firebase_admin import auth
auth.verify_id_token(firebase_auth_token)

It throws the following error:

Token used too early, 1650302066 < 1650302067. Check that your computer's clock is set correctly.

I'm aware that the underlying google auth APIs do check the time of the token, however as outlined here there should be a 10 second clock skew. Apparently, my server time is off by 1 second, however running this still fails even though this is well below the allowed 10 second skew. Is there a way to fix this?

Cosme answered 18/4, 2022 at 17:56 Comment(5)
Did you find a solution? I get this error everysome time, I don't what the problem is. I have tried changing the clock but nothing seems to work. After sometime it works backInartificial
When running on localhost, I've just been restarting my computer. This hasn't happened to me in a production environment yet, but unfortunately I haven't been able to find a better solution.Cosme
Restarting doesn't fix the problem for me. I made a random change in the BE, and it started working again. I wonder if somehow there is something that is getting cache and updating the code fix itInartificial
I am getting this too. I tried restarting, setting the windows time to automatic, and neither worked.Oriana
Adding a bounty to this, seems like a common issueCosme
D
15

This is how the firebase_admin.verify_id_token verifies the token:

verified_claims = google.oauth2.id_token.verify_token(
                    token,
                    request=request,
                    audience=self.project_id,
                    certs_url=self.cert_url)

and this is the definition of google.oauth2.id_token.verify_token(...)

def verify_token(
    id_token,
    request,
    audience=None,
    certs_url=_GOOGLE_OAUTH2_CERTS_URL,
    clock_skew_in_seconds=0,
):

As you can see, the function verify_token allows to specify a "clock_skew_in_seconds" but the firebase_admin function is not passing it along, thus the the default of 0 is used and since your server clock is off by 1 second, the check in verify_token fails.

I would consider this a bug in firebase_admin.verify_id_token and maybe you can open an issue against the firebase admin SDK, but other than that you can only make sure, your clock is either exact or shows a time EARLIER than the actual time

Edit:

I actually opened an issue on GitHub for firebase/firebase-admin-Python and created an according pull request since I looked at all the source files already anyway...

If and when the pull request is merged, the server's clock is allowed to be off by up to a minute.

Dorset answered 14/7, 2022 at 8:36 Comment(7)
Thank you for doing that Frank. I just left a comment asking for an update on your PRLundberg
@DanielJerrehian I actually amended the pull request in the meanwhile and made the clock skew setting an option in the firebase admin app. That way, existing implementations will act exactly as before and only if you put the new clockSkewInSeconds option in the App’s options dictionary or the environment variable, will the behavior change. I think that way the pull request has a higher chance of being accepted.Dorset
Very smart - I agree that it will likely increase the likelihood. Thanks for updating the PR :)Lundberg
Unfortunately still no approval from Google. Any thoughts on how we can push this along?Lundberg
I just got an eMail from GitHub that the pull request was approved by two reviewers. So I presume it will be merged soon.Dorset
I went ahead and approved the PR but I believe someone from Google has to approve as wellLundberg
Still waiting for this to be mergedJurgen
W
2

Had similar problem, solved it by adding "clock_skew_in_seconds=10" in validating definition `

   def validate(auth_token):
    """
    validate method Queries the Google oAUTH2 api to fetch the user info
    """
    try:
        idinfo = id_token.verify_oauth2_token(
            auth_token, requests.Request(), clock_skew_in_seconds=10)

        if 'accounts.google.com' in idinfo['iss']:
            return idinfo

    except:
        return "The token is either invalid or has expired"`
Weedy answered 6/7, 2023 at 8:3 Comment(0)
B
2

I'm having the same problem when running the localhost in my windows 11 PC.I've found a temporary solution by going to Control Panel > Date and Time > Internet Time and changing the synchronization server to time.google.com. If the error persists after re-opening my machine, going to date & time in settings and pressing sync now on additional settings, fixes it until the machine is shut down.

Bustos answered 21/5, 2024 at 11:45 Comment(1)
In addition. a coworker running on ubuntu doesn't have this issue, so I'm guessing it's an error on windows because by default the synchronization server is time.windows.comBustos
C
0

I see this still isn't pulled. To fix it for me I did the following so it would retry to validate the token at the correct time.

@staticmethod
def decode_token(id_token: str) -> FirebaseToken:
    """Decode a Firebase ID token.

    Args:
        id_token (str): A valid Firebase `id_token`, this will be checked to determine if:
            * The token is present and a valid JWT.
            * The token has NOT expired.
            * The token has NOT been revoked.
            * The token has been issued under the correct GCP credentials (API key).

    Returns:
        FirebaseToken: A serialized Firebase ID token.

    Raises:
        HTTPException: If the token fails it's validation.
    """
    try:
        
        payload = JWTBearer.verify_token(id_token)
    except ValueError as err:
        raise HTTPException(
            status_code=401, detail="Unable to verify token"
        ) from err
    except (
        ExpiredIdTokenError,
        InvalidIdTokenError,
        RevokedIdTokenError,
    ) as err:
        # this happens on localhost all the time.
        str_err = str(err)
        if (str_err.find("Token used too early") > -1):
            times = str_err.split(",")[1].split("<")
            time = int(times[1]) - int(times[0])
            sleep(time)
            return JWTBearer.decode_token(id_token)
        raise HTTPException(
            status_code=403, detail=err.default_message
        ) from err
    except CertificateFetchError as err:
        raise HTTPException(
            status_code=500,
            detail="Failed to fetch public key certificates",
        ) from err

    return FirebaseToken(**payload)
Cuttie answered 14/2, 2023 at 23:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.