Skip to content
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

Add a function to fetch auth user from cookies on the server side #223

Closed
Tracked by #265
jasonsilberman opened this issue Jul 3, 2021 · 13 comments
Closed
Tracked by #265
Assignees
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@jasonsilberman
Copy link

Is your feature request related to a problem? Please describe.
I am trying to authenticate requests that come into my Next.js API routes, however, I am not able to pass the token from the useAuthUser hook into the Authorization header. This means that I cannot easily tell if a request is authenticated for my API routes.

Describe the solution you'd like and how you'd implement it
It would make it very easy to achieve this if there was a function to get the AuthUser from the backend by passing in the req object. This would behave similarly to the setAuthCookies function that currently exists.

Alternatively (or additionally), I think it would be a great addition to have function wrappers that one can wrap their API Route handlers in, similar to withAuthUserTokenSSR but specifically focused for server-side API Routes.

Is this a breaking change?
No, this would not be a breaking change.

Describe alternatives you've considered
As far as I can tell, the only alternatives are to write custom logic to read and parse the cookies myself. This seems like a very brittle solution since it will break if the structure of the cookies used by this library will break.

Additionally, I have tried to use the method shown in examples of setting the Authorization header, however, for my use case this is not a viable option.

As far as I can tell, I do not think that this change would require significant changes from this library. I think exposing two functions (possible called getAuthUserFromCookies and withAuthUserTokenAPI or something similar), would solve my use case and greatly expand the functionality and flexibility of this library.

I have really enjoyed porting my own Firebase authentication scheme to this library, however, this is a significant challenge now for me. I'm happy to answer any further questions or possibly contribute as well.

@jasonsilberman jasonsilberman added the enhancement New feature or request label Jul 3, 2021
@mathcrln
Copy link

mathcrln commented Jul 7, 2021

I have a very similar use case and I've been scratching my head for two days about how it could be achieved in a secure way on my end, but I'm left to believe that there isn't. I would love it if this could be implemented natively as it would greatly simplify this kind of workflow when it's just impossible to pass the token in the Authorization header.

@jasonsilberman
Copy link
Author

FWIW, I have copied some of the logic from the internals of this package to replicate this behavior and access the cookies directly. This is a pretty bad idea IMO as it is likely to break if anything internal to this package changes.

@mathcrln
Copy link

mathcrln commented Jul 7, 2021

FWIW, I have copied some of the logic from the internals of this package to replicate this behavior and access the cookies directly. This is a pretty bad idea IMO as it is likely to break if anything internal to this package changes.

Indeed 😅, but as long as it works, that's about the only way to do it, for now, I guess. I hope they could implement something in that direction soon.

@kmjennison
Copy link
Contributor

I agree, a getAuthUserFromCookie probably makes sense to add.

I am not able to pass the token from the useAuthUser hook into the Authorization header

@jasonsilberman Just curious, what prevents you from passing the token in your API requests?

@kmjennison kmjennison added the help wanted Extra attention is needed label Jul 16, 2021
@mathcrln
Copy link

@jasonsilberman Just curious, what prevents you from passing the token in your API requests?

In my case, I'm trying to identify which user is currently authenticated after he has successfully completed an OAUTH2 process to get an access token from an external API. Since the user clicks on a link, I can't pass the access token in any way that allows me to identify him back when he is redirected :/. I could be thinking all of this wrong though 😅, so I'm open to suggestions!

In the meantime, I found an alternative that necessitated me to go from "strict" to "lax" for the sameSite setting, but I'm aware that it's not optimal.

@kmjennison
Copy link
Contributor

@mathcrln I'm not sure I follow. When the app loads after redirect, I'd expect you'd be able to access the token and pass in in API calls (client-side example, server-side example). Or, is the problem that your auth lives on a separate domain from the app?

@iamgbayer
Copy link
Contributor

I agree, a getAuthUserFromCookie probably makes sense to add.

I am not able to pass the token from the useAuthUser hook into the Authorization header

@jasonsilberman Just curious, what prevents you from passing the token in your API requests?

A method likes getAuthUserFromCookie would be awesome

@kmjennison kmjennison mentioned this issue Aug 7, 2021
24 tasks
@gavinharris-dev
Copy link
Contributor

I'm looking at something that will wrap the API route and return a HTTP 401 response if not authenticated (also add the AuthUser into the Request object if I can make that work); this seems like a really nice idea!

With respect to getting the Firebase ID Token, do the 2 examples @kmjennison has linked to not work out / fit your use case? The withAuthUserTokenSSR appears to provide an AuthUser with function getIdToken that resolves to an ID Token (which can then be used as a Bearer token for API requests).

@zaverden
Copy link
Contributor

for those how want to rely on cookie and not send token in headers there is a simple helper:

import { withAuthUserTokenSSR } from 'next-firebase-auth'

const checkServerSideAuth = typeof window !== 'undefined'
  ? null // "withAuthUserTokenSSR" can only be called server-side.
  : withAuthUserTokenSSR({
      whenAuthed: AuthAction.RENDER,
      whenUnauthed: AuthAction.REDIRECT_TO_LOGIN,
      authPageURL: '401',
    })(({ AuthUser }) => ({ AuthUser, props: {} }))

export function withAuthUserTokenAPI(handler) {
  return async (req, res) => {
    const { AuthUser, redirect } = await checkServerSideAuth({ req, res })
    if (redirect) {
      res.status(401).json({ ok: false, code: 'unauthorized' })
      return
    }
    return handler(req, res, AuthUser)
  }
}

and then you wrap your API handler:

export default withAuthUserTokenAPI((req, res, user) => {
  // your code here
})

@Rykuno
Copy link

Rykuno commented Jan 6, 2022

@kmjennison I'll second this use case.

Here is an example that might or might not clear up the use case.

I proxy my graphql requests from Apollo so the server side handles the assignment of the bearer token each request; abstracted from the client side.

If I had a function that set on the server side, I could easily pass it like in the example below upon each request, in one area.
Example

If this function existed, I wouldn't need to pass the context/header info upon every single time I wanted to make a request. This would be an amazing feature.

And @zaverden, I'm relatively ignorant to how this snippit works, but I'm receiving some type errors I have absolutely no idea how to fix other than ignore; but damn it does work lol. https://imgur.com/D9GP7zE

@zaverden
Copy link
Contributor

zaverden commented Jan 7, 2022

@Rykuno for the first error just add async for a callback

-     })(({ AuthUser }) => ({ AuthUser, props: {} }))
+     })(async ({ AuthUser }) => ({ AuthUser, props: {} }))

for the second one - next-firebase-auth has wrong TS typings for withAuthUserTokenSSR (at least for 1.0.0-canary.5 and earlier), that's why there is an error. I suggest to ignore it until typings are fixed. Use @ts-expect-error here

+    // @ts-expect-error wrong typings in lib. remove expect-error if typings are correct now
     const { AuthUser, redirect } = await checkServerSideAuth({ req, res });

Here is typed version: https://gist.github.com/zaverden/9f6579f262ac25b591dd814047e19b30

@kmjennison
Copy link
Contributor

@zaverden If you've identified an incorrect type, please open an issue. Thanks!

@kmjennison
Copy link
Contributor

A getUserFromCookies method was added in #516. It's available in release 1.0.0-canary.13. PR #521 shows a simple demo.

For those following this issue, please let me know if this meets your needs or if you run into any problems using it. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

7 participants