Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
fix: Decoupled proactive token refresh from FirebaseApp #1194
fix: Decoupled proactive token refresh from FirebaseApp #1194
Changes from 2 commits
5b7a89a
8674df3
e7c3588
705801a
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it matter the what order we disarm here? Could this cause a race condition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I felt like we should unregister the listener before clearing out the timer. If we clear the timer first, theoretically it's possible for the listener to fire again and re-initialize the timer. Given both these APIs are synchronous, I don't think it's a real possibility (given how Node.js schedules code), but this seems safer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional suggestion:
You can make this a little simpler if you combine
tokenRefresh
andtokenRefreshTimeout
. You could initializetokenRefreshTimeout
toundefined
initially and then set the schedule right here, which seems more intuitive to me. With the current setup, I have to look atonTokenChange
to figure out the scheduling.I also wonder if we should use
setInterval
. It seems a little more appropriate, but might make things more complicated in some places.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is just intended to register the token change listener. There's no guarantee that the listener will fire immediately. So theoretically it is possible for
tokenRefresh
to be true, whiletokenRefreshTimeout
is not yet set. What we really need is a way to track whether we have registered the listener or not (so we can avoid duplicate registrations, and also unregister it at delete). So I'm renamingtokenRefresh
totokenListenerRegistered
. That should clear up any confusions, and also address the above comment regarding naming.As for
setInterval()
, given that we can receive tokens with arbitrary expiration times from auth (we've seen tokens with expiry times like 30min and 45min), an interval scheduler is not very useful. So we use the token listener to watch for token changes, and schedule refresh events according to the expiry time we get.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC there was no other token refresh listener. If the right action is to immediately ask for a new token from app.INTERNAL should we just remove the parameter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think an even better approach would be to change the signature of the listener to accept a
FirebaseAccessToken
which contains both token and expiry time. That way we wouldn't have to callgetToken()
in the listener at all (we currently do it to get hold of the expiry time).However, this API currently mirrors an API in the JS SDK:
https://github.com/firebase/firebase-js-sdk/blob/ec6ccc7d319732588ceacae0824d6c7551afb026/packages/app-types/private.d.ts#L76
The RTDB implementation expects our App and App.INTERNAL APIs to be compatible with the JS SDK. Therefore we'll need to check with the JS SDK team before making any changes to the listener signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the RTDB component just set
forceRefresh
to true if the expiration time has been hit? That way, we only need to deal with TOKEN_REFRESH_THRESHOLD_MILLIS in one place.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 constants are used for slightly different purposes:
These don't have to be the same value. For instance, we can have FirebaseApp invalidate a token 5 minutes before it expires, but have RTDB trigger the token refresh 10 minutes before the current token expires.
To make the above distinction clear, I'm renaming the constant in firebase-app to
TOKEN_EXPIRY_THRESHOLD_MILLIS
. This constant doesn't have anything to do with refreshing tokens. It's simply when we treat the token as expired.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused. isn't getAccesssToken() already returning a promise? Why do we need to resolve the promise instead of just chaining?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought so too :)
But when I made the change, it actually caused a test failure here:
firebase-admin-node/test/unit/firebase-app.spec.ts
Lines 677 to 691 in 994fd43
This is because the
credential
in this case returns a value which cannot be chained. I'm not sure how much we care about this sort of edge cases, but for now I've opted to keep it as is.