Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firestore query uses stale token after forced refresh #4175

Closed
jadengis opened this issue Dec 6, 2020 · 11 comments · Fixed by #4189
Closed

Firestore query uses stale token after forced refresh #4175

jadengis opened this issue Dec 6, 2020 · 11 comments · Fixed by #4189

Comments

@jadengis
Copy link

jadengis commented Dec 6, 2020

[REQUIRED] Describe your environment

  • Operating System version: Ubuntu 20.04
  • Browser version: Chrome, Firefox both latest
  • Firebase SDK version: 8.1.1
  • Firebase Product: auth, firestore

[REQUIRED] Describe the problem

Steps to reproduce:

In v8.0.0, I am able to perform the following sequence of operations successfully

  • Add a custom claim to a user's token in the backend using admin sdk
  • Force refresh token on the client side using user.getIdTokenResult(true)
  • Immediately perform a query that requires that custom claim in the security rules

In v8.1.1, the above sequence fails when trying to make the query that requires the new claim. I logged the result of user.getIdTokenResult(true) to the console and confirmed that it did in fact has the new claim, which lead me to believe that the firestore sdk is using a stale token. Also after I refresh the page, the query starts working.

Relevant Code:

I'm not sure how to create a complete reproduction, as this sequence involves the admin sdk in the backend to create the custom claim, but I will include some code snippets.

I have a firestore rule that looks like this:

match /listings/{listingId} {
      // store_id is a custom claim added to the users token
      allow read: if return resource.data.state == "available" || resource.data.store.id == request.auth.token.store_id;
}

In the backend I am running the follow code in an http request to create a custom claim on my user:

import admin from "firebase-admin";

...

admin.auth().setCustomUserClaims(userId, {store_id: storeId});

In the front end I have code that does the following in response to the above request.

import firebase from "firebase/app";

...

addStoreIdToUserToken(storeId)
    .then(() => firebase.auth().currentUser)
    .then(user => user.getIdTokenResult(true))
    .then(token => console.log(token.claims)); // The log here shows that the new token has the new claim

After the above chain of promises I make a query like this:

import firebase from "firebase/app";

// storeId is the same as the above code snippet
firebase.firestore().collection("listings").where("store.id", "==", storeId).get();

In version 8.0.0, the above code works, but in 8.1.1 is get a rules violation for the rule snippet above. This leads me to believe firestore is using a stale token without the new claim, even though I forced a refresh.

Thanks for looking into these, please let me know if you require any additional information.

@scottfr
Copy link

scottfr commented Dec 7, 2020

We're experiencing the same issue in 8.1.2. Code using this pattern worked in 7.24.0, but fails in 8.1.2.

Note that after reloading the page, the Firestore queries relying on the new claims will work correctly.

@rosalyntan
Copy link
Member

Hi @jadengis, thanks for filing this issue! This does sound like a bug. Can you try dumping the headers in your Firestore request to check whether or not the correct token is being passed in the request?

@jadengis
Copy link
Author

jadengis commented Dec 8, 2020

Hi @rosalyntan, how can I get this information? Do I need to enable firestore debug logging, our can I just pull the headers from the network tab?

@scottfr
Copy link

scottfr commented Dec 9, 2020

Quick ping on this issue. Do you need any more information on it?

This is a fairly significant regression. We really want to upgrade to Firebase 8 and this is blocking us.

@rafikhan
Copy link
Contributor

rafikhan commented Dec 9, 2020

As @rosalyntan suggested can you pull the headers from the network tab and let us know if the correct token is being used? It will help us isolate where the underlying issue might be.

@scottfr
Copy link

scottfr commented Dec 9, 2020

What are the steps to get the relevant headers? Looking at the Network tab I see a lot of webchannel connections which I assume are the Firestore connections. Inspecting them though, I don't see anything that looks like the custom claims data (either stale or fresh) in the headers.

Where should I be looking for it?

@rafikhan
Copy link
Contributor

rafikhan commented Dec 9, 2020

The token comes from a response to the auth service. The host + path for the auth service will be securetoken.googleapis.com/v1/token and the value should be in the response. You should see this token get passed in the Authorization header or a query string parameter when it talks to Firestore specifically.

You should also enable logging and check it. The SDK's log when a credential change is observed from Auth.

@rafikhan
Copy link
Contributor

Update: We've reproduced this issue on our side and confirmed it's an issue in the Firestore SDK. We're actively investigating this. Thanks to everyone for reporting the issue and helping with the diagnosis.

@Krisell
Copy link

Krisell commented Dec 17, 2020

We're seeing what I think might be the same issue, and it occurs when we try to upgrade from 7.15.5 to 8.2.0 (I haven't been able to isolate the exact version which causes the issue).

We're using signInWithCustomToken before making any calls to Firestore, and when an action occurs that causes signInWithCustomToken to be called again (to switch permissions), the first following request to Firestore uses the old sessionid and fails for permissions reasons. The subsequent requests after this succeed, and we have verified that this is consistent and is not a timing issue.

@schmidt-sebastian
Copy link
Contributor

This has been fixed in Firebase 8.2.1 which should be released today (fingers crossed)

@Krisell
Copy link

Krisell commented Dec 18, 2020

The issue I mentioned was probably not related, and remained in 8.2.1. However, adding a call to .signOut() before signing in with new permissions solved the issue. There is a difference between 7.15.5 and 8.2.1, but the explicit call to .signOut() seems reasonable so it's not an issue for us anymore.

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