admin管理员组

文章数量:1125599

I can manage client-side sessions using useSession from Auth.js (NextAuth v5) with Next.js and TypeScript. However, the return type of useSession includes a "loading" state, and the session is null, even when specifying the required: true option.

I have many components that require a session and would like to avoid handling a nullable session in each of them.

Is there any way to ensure that the session is a non-null object throughout my application?

Attempt 1: Check session in wrapper component

This comment from committer provides a useful JavaScript solution. However, in TypeScript, useSession still returns a type that includes a nullable session, requiring explicit handling in each child component.

Attempt 2: Wrapping components and passing the session as a prop

I tried handling the nullable session in a wrapper component, such as <EnsureSession>. However, this approach fails type checking. While using a dummy session object could potentially resolve the issue, I believe this approach is not ideal.

//  app/page.tsx
<EnsureSession>
  <Child />   // Error: session prop is not specified
</EnsureSession>

//  Child.tsx
interface ChildProps {
  session: Session
}

const Child: FC<ChildProps> = ({ session }) => {


//  EnsureSession.tsx
type EnsureSessionComponent = ReactElement<{ session: string }>;

export function EnsureSession({ children }: { children: React.ReactNode }) {
  const { data: session } = useSession()
  const router = useRouter()
  useEffect(() => {
    if (!session) {
      router.push('/login')
    }
  }, [session, router])

  if (!session) {
    return <div>Loading...</div>
  }

  const childrenWithSession = React.Children.map(children, (child) => {
    if (React.isValidElement(child)) {
      return React.cloneElement(child as EnsureSessionComponent, { session: '' })
    }
    return child;
  })
  return childrenWithSession
}

Attempt 3: Handling session with a Higher-Order Component (HOC)

I attempted to handle nullable sessions with an HOC. However, this approach fails at run-time. because client-side functions cannot be called from server-side components.

//  WithSession.tsx
'use client'
export function WithSession<T>(Component : React.FC<T>): React.FC<Omit<T, 'session'>> {
  const { data: session } = useSession()
  const router = useRouter()
  useEffect(() => {
    if (!session) {
      router.push('/login')
    }
  }, [session, router])

  if (!session) {
    return (_props: Omit<T, 'session'>) => {
      return <div>Loading...</div>
    }
  }

  return (props: Omit<T, 'session'>) => {
    return <Component {...(props as T)} session={session} />
  }
}

// app/page.tsx
const ChildWithSession = WithSession<ChildProps>(Child)  // Runtime Error: can't call function
return (
  <ChildlWithSession />
)

Attempt 4: Wrapping useSession function

Also, the following approach is not ideal for several reasons.

  • It requires extracting internal types from next-auth, which are not exported
  • Returning a dummy session during the loading state

I didn't check behavior, I am concerned that redirect to /login while loading.

//  Following types are not exported from next-auth
export type EnsureSessionContextValue = {
    update: UpdateSession;
    data: Session;
    status: "authenticated";
}

export interface UseSessionOptions<R extends boolean> {
    required: R;
    /** Defaults to `signIn` */
    onUnauthenticated?: () => void;
}

function useEnsureSession<R extends boolean>(options?: UseSessionOptions<R>): EnsureSessionContextValue {
  const context = useSession(options)
  const router = useRouter()
  if (!context.data) {
    router.push('/login')
    // Should return dummy session...
    return { data: dummy } as EnsureSessionContextValue
  }

  return context
}

本文标签: nextjsEnsuring NonNullable Session in Authjs(NextAuth v5) with TypeScriptStack Overflow