awinogrodzki / next-firebase-auth-edge

Next.js Firebase Authentication for Edge and Node.js runtimes. Compatible with latest Next.js features.
https://next-firebase-auth-edge-docs.vercel.app/
MIT License
499 stars 43 forks source link

Error in middleware when refreshing an expired token #9

Closed steve-marmalade closed 1 year ago

steve-marmalade commented 1 year ago

Hello again.

I have only seen this issue while developing locally, and it happens only after I come back from a long break (as evidenced by the need to "refresh an expired token"). I did check that the auth cookies themselves had not expired.

I wonder if you have a sense of the root cause? Even if this error is expected, it would be convenient if the function just returned null (and then the middleware would route as appropriate for an unauthenticated user).

error - node_modules/next-firebase-auth-edge/lib/auth/index.js (61:0) @ refreshExpiredIdToken
error - Error during refreshing expired token: {"error":{"code":400,"message":"USER_NOT_FOUND","status":"INVALID_ARGUMENT"}}
null

image

Manually clearing the cookies and reloading the page resolves the issue.

steve-marmalade commented 1 year ago

Ah, I believe I understand how to reproduce:

Then the library will attempt to use the cookies to get a new token, resulting in the USER_NOT_FOUND error.

awinogrodzki commented 1 year ago

👋 Hey @steve-marmalade! Thanks for the feedback.

Just to confirm we are on the same page:

If you delete the user from Firebase Auth, but login before the token has expired, it is working as expected? I presume that token is validated against expiration date and everything works fine.

To be honest, USER_NOT_FOUND error when trying to refresh the token of non-existing user seems informative and just returning null in such case could be misleading to some users during debugging.

At the same time I see that your development cycle could be improved by just returning null when there's no user for given token.

Currently, we just throw an error received from Firebase Auth API. I would need to improve it to return FirebaseError with appropriate code. That way, you could create a decorator function that will help your use-case:

async function getTokensOrNull(...) {
  try {
     return await getTokens(...);
  } catch (e: unknown) {
      if ((e as FirebaseAuthError).code === AuthClientErrorCode.USER_NOT_FOUND.code) {
        return null;
      }

     throw e;
  }
}

I'll post a working example once I finish improving error handling.

What do you think?

steve-marmalade commented 1 year ago

Yep, that sounds very reasonable to me!

awinogrodzki commented 1 year ago

👋 @steve-marmalade!

"USER_NOT_FOUND" error is now being handled and re-thrown as FirebaseAuthError in next-firebase-auth-edge@0.2.15

You can map the error to null using isUserNotFoundError function as follows:

    import { isUserNotFoundError } from 'next-firebase-auth-edge/lib/auth';

    async function getTokensOrNull(...) {
      try {
        return await getTokens(...);
      } catch (e: unknown) {
        if (isUserNotFoundError(e)) {
          return null;
        }

        throw e;
      }
    }