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

Getting Auth Session in a server component, Set CallbackURL issue! #483

Open
aifirstd3v opened this issue Apr 29, 2024 · 6 comments
Open

Comments

@aifirstd3v
Copy link

aifirstd3v commented Apr 29, 2024

I'am developing a simple NextJS app with hono & auth.js.

My Question is

  1. How to make a valid hook function to get the auth session normally in server components. auth.js middlware only supports to get it in client components through useSession hook or session provider?
  2. callbackUrl doesn't work with signIn(NextAuth library works! tho), I've inspected the cookie in the browser. After processing signIn and authHandler, the middleware overwrites the authjs.callback-url cookie for the default callback url. So even if I call setCookie to overwrite the cookie, it doesn't work.

For sure, The Client useSession works like the official document(readme).

import { useQuery } from '@tanstack/react-query'

export const useSession = () => {
  const { data, status } = useQuery({
    queryKey: ['session'],
    queryFn: async () => {
      const res = await fetch('/api/auth/session')
      // console.log('useSession res: ', res)

      return res.json()
    },
    staleTime: 5 * (60 * 1000),
    gcTime: 10 * (60 * 1000),
    refetchOnWindowFocus: true
  })
  return { session: data, status }
}
'use client'
import { useSession } from '@/hooks/use-session'
export default function page() {
  const { status, session } = useSession()
...

But, I'd like to get an auth session from a server component in NextJS. So, I created a hook for this purpose.

export async function checkServerSession() {
  const fetchUrl = process.env.BASE_URL + '/api/auth/session'
  // console.log("fetchUrl: ", fetchUrl)
  const res = await fetch(fetchUrl)
  const result = await res.json() 
  console.log('checkServerSession res: ', result)

  return result
}
import 'server-only'
import { checkServerSession } from '@/hooks/checkServerSession'
import { redirect } from 'next/navigation'

async function layout({ children }: { children: ReactNode }) {
  const session = await checkServerSession()
  

  if (!session) {
    console.log("No Session Found")
    redirect('/signin?callbackUrl=/finance')
  } else {
    console.log('Session Found: ', session)
  }
  ...

However, The session is always Null although I have've signed-in and had an auth session after github(provider) login.
I need get a session in server components not client components because of a special purpose(to check the auth status in the server more securely without evaluating a client page component. )
Next-Auth library has a getServerSession() but it seems that hono auth.js middleware doesn't have such a thing.

signIn('GitHub', { redirect: false, callbackUrl: searchParams.get('callbackUrl') || '/' })
const app = new Hono()
app.use(logger(customLogger))

app.use(
'*',
cors({
  origin: (origin) => origin,
  allowHeaders: ['Content-Type'],
  allowMethods: ['*'],
  maxAge: 86400,
  credentials: true
})
)

app.use('*', initAuthConfig(getAuthConfig))
const authMiddleware = async (c: Context, next: Next) => {
console.log('👍Hono authMiddleware!')
// console.log("Context: ", c)
await next()
}
const setCookieMiddleware = async (c: Context, next: Next) => {
console.log('👍Hono setCookieMiddleware!')
setCookie(c, 'authjs.callback-url', 'http://localhost:3000/finance')
await next()
}
app.use('/api/auth/*', authMiddleware, setCookieMiddleware, authHandler())

Any idea would be helpful 👍

@yusukebe
Copy link
Member

yusukebe commented May 1, 2024

Hi @aifirstd3v

@divyam234 Do you have any idea?

@divyam234
Copy link
Contributor

divyam234 commented May 1, 2024

@aifirstd3v If you are using nextjs you should use next-auth only as both of them are tightly coupled. Your checkServerSession implementation will not work as on server side you need to get session from cookies rather than calling fetch. Also getting auth session requires passing honojs context which is not possible in server components.But you can write simple authChecker in server components also.

import { Auth } from '@auth/core'
import type { Session } from '@auth/core/types'
import type { JWT } from '@auth/core/jwt'
import type { AdapterUser } from '@auth/core/adapters'

type AuthUser = {
  session: Session
  token?: JWT
  user?: AdapterUser
}

function getServerSession(req:Request) {
  const config = initAuthConfig()  // Authjs config
  config.secret ??= process.env.AUTH_SECRET
  config.basePath ??= '/api/auth'
  config.trustHost = true
  const origin = process.env.AUTH_URL ? new URL(process.env.AUTH_URL ).origin : new URL(c.req.url).origin
  const request = new Request(`${origin}${config.basePath}/session`, {
    headers: { cookie: req.headers.get('cookie') ?? '' },
  })

  let authUser: AuthUser = {} as AuthUser

  const response = (await Auth(request, {
    ...config,
    callbacks: {
      ...config.callbacks,
      async session(...args) {
        authUser = args[0]
        const session = (await config.callbacks?.session?.(...args)) ?? args[0].session
        const user = args[0].user ?? args[0].token
        return { user, ...session } satisfies Session
      },
    },
  })) as Response

  const session = (await response.json()) as Session | null

  return session && session.user ? authUser : null
}

You can add this in Nextjs middleware

@aifirstd3v
Copy link
Author

aifirstd3v commented May 2, 2024

@divyam234 Thing is how to call the getServerSession(req) in server components with Request parameter? I don't know how to pass the req in nextjs server component..

Also, setting callbackUrl doesn't work. After logging, there is no way return to the callback url that I set.

Well..If I use this auth middleware in react 19 with server components, I think it would be very useful to have such a feature for a server component.

@divyam234
Copy link
Contributor

divyam234 commented May 3, 2024

@aifirstd3v you dont have to use this in server component use this in nextjs midleware which gives you request object and run this for client routes you want to secure.

@aifirstd3v
Copy link
Author

aifirstd3v commented May 5, 2024

@aifirstd3v Of course, it should work for the NextJS middleware because it provides the Request/Response. I just wanted to know how to use such a thing in server components freely :).
I think it would be better to use Next-Auth itselt for NextJS apps like you mentioned ! Thanks anyway for helping me.

@beorn
Copy link

beorn commented May 26, 2024

The original problem is probably related to #537 (which now includes a fix) - getAuthUser() fails because origin gets set without taking into consideration the X-Forwarded-* headers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants