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

getIdTokenResult() with forceRefresh reruns snapshot listeners that are set to includeMetadataChanges #8686

Open
GaurangTandon opened this issue Dec 25, 2024 · 4 comments

Comments

@GaurangTandon
Copy link

GaurangTandon commented Dec 25, 2024

Operating System

macOS Ventura

Environment (if applicable)

Google Chrome 131.0.6778.205 (Official Build)

Firebase SDK Version

10.11.0

Firebase SDK Product(s)

Firestore, Auth

Project Tooling

Default React app

Detailed Problem Description

Context

  1. The given code requests a new user token - with forceRefresh set to true - every 7 seconds.
  2. The code also sets a onSnapshot listener to a test document with includeMetadataChanges set to true

Expected behavior

  1. The onSnapshot listener should only run once when the data loads

Actual behavior

  1. The onSnapshot listener runs each time the new token is generated. The snapshot.metadata.fromCache property toggles between true and false each time the listener runs.

Further observation: Setting forceRefresh to false in getIdTokenResult fixes the issue

Conclusion: It's not obvious why force refreshing the token changes the metadata on the snapshot causing the listener to rerun.

The behavior might be a bug. Hence I have filed this report.
If it's not a bug, I would like to know if there's a way to skip these unnecessary runs of the snapshot listener.

Steps and code to reproduce issue

import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { collection, doc, getFirestore, initializeFirestore, onSnapshot, setLogLevel } from 'firebase/firestore';
import React from 'react';
import { createRoot } from 'react-dom/client';

const root = createRoot(
  document.getElementById('root')
);

const firebaseConfig = {
  ...your config...
};

const firebaseApp = initializeApp(firebaseConfig);
initializeFirestore(firebaseApp, {});
const user = getAuth().currentUser; // initialize auth

setTimeout(() => {
  onSnapshot(doc(collection(getFirestore(), 'test_collection'), 'test_document'), { includeMetadataChanges: true, }, (snapshot) => {
    let data = null;
    if (snapshot.exists()) {
      data = snapshot.data();
    }
    console.log('users readonly data', data, snapshot.metadata);
  }, undefined);
}, 1000);

setInterval(async () => {
  console.log('token got', await getAuth().currentUser.getIdTokenResult(true));
}, 7_000);

function App() {
  return <div>'Hello World'</div>;
}

root.render(<App />);
@GaurangTandon GaurangTandon added new A new issue that hasn't be categoirzed as question, bug or feature request question labels Dec 25, 2024
@google-oss-bot
Copy link
Contributor

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@lehcar09 lehcar09 added api: auth api: firestore and removed new A new issue that hasn't be categoirzed as question, bug or feature request labels Dec 25, 2024
@milaGGL milaGGL self-assigned this Dec 27, 2024
@milaGGL
Copy link
Contributor

milaGGL commented Dec 27, 2024

Hi @GaurangTandon , thank you for reporting this issue. Could you please confirm if the app also gets refreshed every 7 seconds, and re-call a new onSnapshot? If yes, the new snapshot will try to read from cache first, and then updates the metadata when it received response from server. That could be the reason you are seeing repeated fromCache: true/false.

Also, what is the security rule for reading documents? Does it have restrictions based on authentication status? Can you add a onAuthStateChanged to monitor auth status?

@GaurangTandon
Copy link
Author

Hi @milaGGL

Could you please confirm if the app also gets refreshed every 7 seconds, and re-call a new onSnapshot?

The webpage is not being reloaded. There is a setInterval (with 7 second interval) in the code to fetch new token with force refresh, as shown in the code. I believe you would be able to reproduce the issue with the provided code.

what is the security rule for reading documents?

I was able to reproduce the issue on a test Firebase project with full read/write permissions.

@milaGGL
Copy link
Contributor

milaGGL commented Jan 8, 2025

Refreshing the snapshot listener on new auth tokens is an intended behaviour to keep the listener "alive" when auth token expired naturally, however, it would have adverse effect on situations where the auth token force refreshed frequently. Unfortunately, there is no work around for it, except not listening to metadata changes, which I assume is required in your case.

This issue is added to our backlog , googler please see b/388491409. However, we are under capacity constraints recently, and I cannot provide an ETA for a fix. Sorry for the inconvenience.

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

No branches or pull requests

6 participants