Firebase-js-sdk: onIdTokenChanged never called when token refreshes

Created on 24 Apr 2020  路  5Comments  路  Source: firebase/firebase-js-sdk

[REQUIRED] Describe your environment

  • Operating System version: MacOS 10.15.4
  • Browser version: Chrome 81
  • Firebase SDK version: [email protected]
  • Firebase Product: auth

[REQUIRED] Describe the problem

I鈥檓 running into an issue with the JS SDK and the onIdTokenChanged method (https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onidtokenchanged). Specifically, it doesn鈥檛 appear to get called when the token refreshes.

We use the Firebase Auth JWT in all requests to our API. If I leave a browser open for an extended period of time, the token never refreshes, and ultimately I start getting this error when trying to decode it:

Error: Firebase ID token has expired. Get a fresh ID token from your client app and try again (auth/id-token-expired). See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.

I鈥檝e done extensive logging around this method and it appears that the token expires and onIdTokenChanged never gets called. Is this expected behavior?

Steps to reproduce:

I have a very vanilla implementation of Firebase Auth. I haven't changed any setting or changed the way persistence is done.

Relevant Code:

firebase.auth().onIdTokenChanged((user) => {
  if (user) {
    user.getIdToken().then((token) => {
      clearCachedClient(token)       
      userCallback()
    })
  } else {
    clearCachedClient(null)
  }
})
auth documentation

Most helpful comment

Yeah, I guess that wasn't clear from reading the documentation. You may want to disclose that and even put some more color around it on how tokens get refreshed. Here's what we ended up doing to get this fixed:

const getCurrentUserAuthorization = async () => {
  const currentUser = firebase.auth().currentUser
  if (currentUser) {
    const token = await currentUser.getIdToken()
    return `Bearer ${token}`
  } else {
    return ''
  }
}

Fortunately, the GraphQL library that we're using supports asynchronous headers (it'll resolve them before making a request), so this ended up working. But, I initially assumed that Firebase would be automatically keeping my token refreshed for me.

Maybe update the docs as an action item?

All 5 comments

I'm sad to hear that your experience with using Firebase was poor. To help you relive the good times I've assigned sam to this bug instead.

Hi Joel,

The token refreshes lazily when interacting with other Firebase services (or if you call getIdToken(true)). Is your API using another Firebase SDK or are you passing the user token directly to another service? If the latter, you'll need to handle refreshing the token yourself.

Yeah, I guess that wasn't clear from reading the documentation. You may want to disclose that and even put some more color around it on how tokens get refreshed. Here's what we ended up doing to get this fixed:

const getCurrentUserAuthorization = async () => {
  const currentUser = firebase.auth().currentUser
  if (currentUser) {
    const token = await currentUser.getIdToken()
    return `Bearer ${token}`
  } else {
    return ''
  }
}

Fortunately, the GraphQL library that we're using supports asynchronous headers (it'll resolve them before making a request), so this ended up working. But, I initially assumed that Firebase would be automatically keeping my token refreshed for me.

Maybe update the docs as an action item?

Yep, that seems reasonable. I'll follow up with the documentation. I'll also raise some sort of auto-renewal feature request with the team as something to consider in the future.

@samhorlbeck Just ran into this issue with auth.onIdTokenChanged(observer) not firing and we ended-up with a getIdToken(forceRefresh) as @joelpoloney mentioned above. It would be great to have the documentation updated to clarify this lazy refresh behavior. Another suggestion would to provide a client-side helper function to trigger a refresh before the idTokenResult.expiration

Was this page helpful?
0 / 5 - 0 ratings