gladly-team / next-firebase-auth

Simple Firebase authentication for all Next.js rendering strategies
https://nfa-example-git-v1x-gladly-team.vercel.app/
MIT License
1.34k stars 290 forks source link

Request for a feature to secure custom API endpoints. #450

Closed hunghvu closed 2 years ago

hunghvu commented 2 years ago

Is your feature request related to a problem? Please describe. It appears the package does not provide server-side authentication for custom Next.js API endpoints. The current features only work for SSR pages with Firebase API call (e.g., Render page with populated information or redirect to Auth page), but there is nothing like a middleware, guard for custom endpoints.

A practical example is when users want to host applications on Google Cloud and use Google Identity Platform (IdP) for their organization authentication (for regulatory compliance purposes). Firebase/Admin SDK is required to interact with IdP, but users don't use any other Firebase functionalities. If there is an internal an endpoint api/get-info/, only authenticated users are able to access it.

Describe the solution you'd like and how you'd implement it

  1. Using Firebase's verifySessionCookie internally, we need a unified cookie (#190). The two current cookies AuthUser and AuthUserTokens do not work with that API. This can be done either by having an option to return a unified cookie, or perform a server-side processing to transform the two current cookies into one.
  2. In InitConfig, have an option for onVerifySessionCookieError.
  3. Have an API to access verifySessionCookie.
  4. This can also utilize Next.js middleware feature (https://github.com/gladly-team/next-firebase-auth/issues/418).

Is this a breaking change? No.

Describe alternatives you've considered If using Firebase Admin SDK directly, then this is achievable via a middleware with Firebase's verifySessionCookie. However, the downside is users need to rebuild the whole authentication flow, which is not desirable.

There is a chance my proposal is wrong in some ways, please feel free to correct the mistakes.

kmjennison commented 2 years ago

Thanks for the issue.

If you're looking to protect an endpoint, here's an example using the Authorization header and a Firebase token: https://github.com/gladly-team/next-firebase-auth/blob/main/example/pages/api/example.js

You can create a reusable module to handle authorization across multiple endpoints.

If you're specifically looking to use cookies for auth, there's an open issue to support the functionality: #223

Possibly related: #418, #278

Do these address your issue? If so, I'll close this.

hunghvu commented 2 years ago

Thanks for the issue.

If you're looking to protect an endpoint, here's an example using the Authorization header and a Firebase token: https://github.com/gladly-team/next-firebase-auth/blob/main/example/pages/api/example.js

You can create a reusable module to handle authorization across multiple endpoints.

If you're specifically looking to use cookies for auth, there's an open issue to support the functionality: #223

Possibly related: #418, #278

Do these address your issue? If so, I'll close this.

  1. Yes, that addresses my issue. I did miss the example.
  2. Am I right to say the front page documentation is lacking in this regard? It's mostly about securing pages, not endpoints. Although, If I read the documentation more carefully, I may not have opened this issue.
  3. Regarding verifyIdToken in the example, it seems token revocation is not checked or is it done underneath? What I mean is a call using verifyIdToken(yourID, true).
kmjennison commented 2 years ago
  1. Great!
  2. Yes, this can be improved. We could add an example in the README and maybe call it out near the top. Feel free to open an issue or PR.
  3. That's handled under the hood by Firebase.

On Fri, Mar 18, 2022, 6:07 PM Hung Vu @.***> wrote:

Thanks for the issue.

If you're looking to protect an endpoint, here's an example using the Authorization header and a Firebase token: https://github.com/gladly-team/next-firebase-auth/blob/main/example/pages/api/example.js

You can create a reusable module to handle authorization across multiple endpoints.

If you're specifically looking to use cookies for auth, there's an open issue to support the functionality: #223 https://github.com/gladly-team/next-firebase-auth/issues/223

Possibly related: #418 https://github.com/gladly-team/next-firebase-auth/issues/418, #278 https://github.com/gladly-team/next-firebase-auth/issues/278

Do these address your issue? If so, I'll close this.

  1. Yes, that addresses my issue. I did miss the example.
  2. Am I right to say the front page documentation is lacking in this regard? It's mostly about securing pages, not endpoints. Although, If I read the documentation more carefully, I may not have opened this issue.
  3. Regarding verifyIdToken in the example, it seems token revocation is not checked or is it done underneath? What I mean is a call using verifyIdToken(yourID, true).

— Reply to this email directly, view it on GitHub https://github.com/gladly-team/next-firebase-auth/issues/450#issuecomment-1072850041, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABNGLZLOUCWYI7DOGD7Q3SLVAT5AZANCNFSM5Q4WLFTQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you commented.Message ID: @.***>

hunghvu commented 2 years ago

This discussion might derail from an original PR purpose, but please correct me if I'm wrong.

I believe Firebase does not check for token revocation by default. An explicit option must be added. This is under the assumption that a user does not use any Firebase features (e.g. security rules) aside from authentication service. For example, a server is on another cloud provider.

References

  1. Verify ID Token documentation
  2. Manage user session documentation
kmjennison commented 2 years ago

Sorry, I wasn't very clear. Yes, you're right about that: we don't pass true to the second argument to Firebase's verifyIdToken, so this library won't know immediately that a token was revoked. However, I believe revoked tokens will lose access within an hour, because attempts to refresh the ID token will fail (whether called by the Firebase JS SDK or by this library's Firebase Admin logic). Does this sound right to you?

hunghvu commented 2 years ago

You're right, the short-lived ID Token will expire after an hour. A revoked token cannot be refreshed afterward. However, during that 1-hour timeframe, the application is vulnerable if a token is compromised. Or does next-firebase-auth have a way to prevent the scenario underneath?

// Securing an API
try {
      await verifyIdToken(token) // Always true unless one hour has passed after the revocation.
} catch (e) {
      return res.status(403).json({ error: 'Not authorized' })
}
kmjennison commented 2 years ago

during that 1-hour timeframe, the application is vulnerable if a token is compromised

That's correct.

Fixing this is out of scope for this library, but we could expose an option to allow developers to always check for token revocation. In that case, the library would pass true to the second argument to Firebase's verifyIdToken. That would come with the performance hit of a round-trip call to Firebase. (Edited: added missing word "could".)

I believe there are discussions elsewhere about how other apps deal with this in Firebase; for example, you might keep recently-revoked UIDs in memory for a quick lookup on your auth server.

hunghvu commented 2 years ago

but we expose an option to allow developers to always check for token revocation

May I ask how to use that option? As far as I can see withAuthUserTokenSSR does have a token revocation check, but it is not designed for API. Both initConfig and verifyIdToken do not seem to expose the boolean option.

However. we have a refresh token (retrievable from firebase-admin-sdk or cookies?) as a second argument that immediately triggers a refresh action when passing to verifyIdToken. This workaround is equivalent to check revocation, is that what you mean? If that is the case then I think the document is unclear regarding this.

kmjennison commented 2 years ago

@hunghvu My mistake, I missed typing word that changed this a lot. "we could expose an option" -- we don't have this option now but could consider adding it if developers need it.

hunghvu commented 2 years ago

Sounds great. Thanks for answering all of my questions. From the discussion, the following may have their own issues.

  1. Improve README on ways to secure API endpoints.
  2. Option to expose check ID token verification option.

I will close this issue.