Closed realexp3rt closed 2 weeks ago
Hi @realexp3rt, thanks for the report. I tried replicating, but I wasn't able to reproduce the error. If I can replicate the issue, I can have a better look into it. Please share a minimal, but complete sample of a project that I can run locally.
I don't know but it seems like the issue occurs whenever someone signs in. The already signed in user will have this issue for a couple of seconds then it will go away after a couple re-logins.
Here is my /api/user.js which fetchs the user information from the database whenever the user refreshes the page:
import {parse} from "cookie";
import admin from "firebase-admin";
import { readUser } from "../../services/read";
import {config} from "dotenv";
const serviceAccount = require("../../config/firebase.json");
config();
try {
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://**.firebasedatabase.app",
});
} catch (error) {
if (!/already exists/u.test(error.message)) {
console.error("Firebase admin initialization error", error.stack);
}
}
function getMinutesLeftUntilExpiry(expirationTimestamp) {
// Get the current UTC Unix timestamp in seconds
const currentTimestamp = Math.floor(Date.now() / 1000);
// Convert the expiration timestamp to minutes and subtract the current timestamp
const minutesLeft = Math.floor((expirationTimestamp - currentTimestamp) / 60);
return minutesLeft;
}
// Example usage:
export default async function handler(req, res) {
try {
const cookies = parse(req.headers.cookie || '');
const accessToken = cookies.accessToken;
const decodedToken = await admin.auth().verifyIdToken(accessToken);
// const decodedToken = jwt.decode(accessToken);
if (decodedToken) {
const { exp } = decodedToken;
const { user_id } = decodedToken;
let user = await readUser(user_id)
console.log(user);
let currentTier = user.tier
let pros;
let usage;
let currentSubDate;
let currentSubType;
if (currentTier === "pro")
{
pros = user.pros
usage = user.usage
decodedToken.pros = pros;
decodedToken.usage = usage;
}
if (currentTier === "rec" || currentTier === "special") {
currentSubDate = user.subDate;
currentSubType = user.subType;
}
decodedToken.tier = currentTier;
const remainingMinutes = getMinutesLeftUntilExpiry(exp);
if (remainingMinutes < 1) {
res.status(401).json({ error: 'Token has expired' });
return;
}
decodedToken.accessToken = accessToken;
res.status(200).json(decodedToken);
} else {
res.status(200).json(null);
}
} catch (error) {
// console.error('Error retrieving user:', error);
res.status(500).json({ error: 'Failed to retrieve user' });
}
}
It's linked with an AuthContext to be synced all over the app.
And for /api/signin.js
export default async function handler(req, res) {
if (req.method === "POST") {
const { email, password } = req.body;
try {
const result = await signInWithEmailAndPassword(auth, email, password);
let idToken = await result.user.getIdToken();
res.setHeader('Set-Cookie', `accessToken=${idToken}; Path=/; Secure; SameSite=Lax`);
res.status(200).json({ success: true });
} catch (e) {
console.error(e);
res.status(500).json({ success: false, error: "Sign-in failed" });
}
} else {
res.status(405).json({ success: false, error: "Method not allowed" });
}
}
Notice that i'm taking the approach of server-side with sign in and database reads. I don't want anything exposed to the client.
Thanks for the additional code snippet, @realexp3rt. I just want to clarify my investigation regarding this issue since we have two error messages here: @firebase/firestore: Firestore (9.22.0): GrpcConnection RPC 'Listen' stream 0x367a9933 error. Code: 1 Message: 1 CANCELLED: Disconnecting idle stream. Timed out waiting for new targets. [FirebaseError: Missing or insufficient permissions.] { code: 'permission-denied', customData: undefined, toString: [Function (anonymous)] }
For the permission error, could you verify that the user is currently signed-in before performing the read/write in the database. There shouldn't be any issue if the user is signed-in before doing any activity on the database.
For the grpc issue, I noticed that there are similar reported connectivity issue in version 9.22.0
. Could you try the recommended steps and additional info asked by one of our engineer on this similar issue:
Could you please try set FirestoreSettings.experimentalAutoDetectLongPolling to false to explicitly disable long polling?
Also it would be especially helpful if you could gather logs from https://debug-my.firebaseapp.com/ when you experience this issue. Thanks!
Lastly, there are a lot of fixes on Firebase Firestore, would you mind trying to the update the SDK version that you're using and see if the issue persists?
It looks like.. when a user signs in, every signed in user session changes to this new user thus rendering insufficient permissions since the uid won't match! how is this happening I don't understand! can you figure it out from these code snippets?
Seems like an unsynchronized auth users. I did await auth.currentUser.email; in my user.js and saw the output. Whenever a new user signs in the whole app auth changes to that user and to be honest.. i'm not sure why
Hi @realexp3rt, I used the given code snippet you've provided, unfortunately, I'm not encountering the error. I'm not totally clear how you are using the signInWithEmailAndPassword
on the server side as it is not available in firebase-admin. It's possible that we're missing something from the given code snippet. I think the difference in our configuration setup may also be the reason why I'm unable to reproduce the behavior. That said, I believe in order to move this forward, a minimal reproducible example will allow us to look at this issue on every angle carefully, resulting to a more speedy resolution. By the way, could you try to update the SDK version that you're using and see if the issue persists? We usually advise this to our developers in order to avoid issues that may have been resolved in the most recent versions. Thanks!
Well I fixed it. TL;DR since i'm using server-side auth and auth isn't synced in client-side whenever a user signs in it changes the whole app currentUser to the last signed in. And since i'm using a request.auth.uid == userId; it wouldn't give them permession. So I deleted that and everything worked well. Since i'm verifying the idToken in the back-end everything should be good. Sorry for the trouble. But the timeout issue still exists. I updated my SDK but how exactly can I set experimentalAutoDetectLongPolling
to false
? I couldn't figure it out with my setup. Please refrence my init setup above.
Thanks!
Glad to know that syncing authentication between client and server fixed the issue. To enable experimentalAutoDetectLongPolling
, you have to use the initializeFirestore()
rather than getFirestore()
then set the setting as below:
const firestore = initializeFirestore(app, {
experimentalAutoDetectLongPolling: false,
})
Thanks for your efforts. <3
Operating System
Linux
Browser Version
-
Firebase SDK Version
9.22.0
Firebase SDK Product:
Database, Firestore
Describe your project's tooling
Next.js app
Describe the problem
Lately i've been facing issues when I switched the project to another server. Sometimes when a user reads the database through this function:
I get these errors occasionally but not every time.
@firebase/firestore: Firestore (9.22.0): GrpcConnection RPC 'Listen' stream 0x367a9933 error. Code: 1 Message: 1 CANCELLED: Disconnecting idle stream. Timed out waiting for new targets.
[FirebaseError: Missing or insufficient permissions.] { code: 'permission-denied', customData: undefined, toString: [Function (anonymous)] }
Everything was working before i'm not sure what the issue is.
Here is my firebase init code:
And here are my security rules
Steps and code to reproduce issue
I'm not sure