next.jsnext.js13next-auth

App Router - next-auth route handler - How to access the Request BEFORE it is sent to NextAuth?


Summary

Using next.js App Router - How do I access the Request BEFORE it is sent to NextAuth? I want to be able to replicate the following which is achievable with the next.js Pages Router:

// /api/auth/[...nextauth].js
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
import GoogleProvider from "next-auth/providers/google"

export default async function auth(req, res) {
  const providers = [
    CredentialsProvider({
      // ...
    }),
    GoogleProvider({
      // ...
    })
  ]

  // Based on https://next-auth.js.org/getting-started/rest-api#get-apiauthsignin
  const isDefaultSigninPage = req.method === "GET" && req.query.nextauth.includes("signin")
  if (isDefaultSigninPage) providers.pop()

  return await NextAuth(req, res, {
    providers,
    // rest of your config ...
  })
}

Additional information

For instance how can the following App Router - Route handler:

import NextAuth from "next-auth"

const handler = NextAuth({
  ...
})

export { handler as GET, handler as POST }

be adjusted to expose the Request similar to Pages Router like the following:

import type { NextApiRequest, NextApiResponse } from "next"
import NextAuth from "next-auth"

export default async function auth(req: NextApiRequest, res: NextApiResponse) {
  // Do whatever you want here, before the request is passed down to `NextAuth`
  return await NextAuth(req, res, {
    ...
  })
}

Solution

  • TL;DR

    Just wrap the handler and export it with the appropriate naming:

    import NextAuth from "next-auth"
    
    const handler = NextAuth({
      ...
    })
    
    async function auth(req, body) {
      const response = handler(req,body);
      const res = await response; // If you want to access the response object to modify
      return res;
    }
    
    export { auth as GET, auth as POST }
    

    My step-by-step process

    I know that this is an old post and you might have already found the answer, but as someone that was struggling in finding a way to get the response object I'm gonna leave my findings here to help anyone stuck at this.

    As per the NextJs documentation on Route Handlers: NextJS - Route Handlers. A route handler is nothing more than a specifically named function (using HTTP methods) that receives a Request and a body (as far as my findings goes) and returns a Response object.

    Now, acording to Next-auth documentation we have:

    Internally, NextAuth.js detects that it is being initialized in a Route Handler (by understanding that it is passed a Web Request instance), and will return a handler that returns a Response instance. A Route Handler file expects you to export some named handler functions that handle a request and return a response. NextAuth.js needs the GET and POST handlers to function properly, so we export those two.

    That was the passage that helped get the response (mainly the boldened one). With regards with your question we have (as said by Kevin11 in the comments):

    export default async function auth(req: NextApiRequest, res: NextApiResponse) {
      // Do whatever you want here, before the request is passed down to `NextAuth`
      return await NextAuth(req, res, {
        ...
      })
    }
    

    So we just need to wrap the returned handler, and export the wrapper function then we can have access to both the request and response:

    import NextAuth from "next-auth"
    
    const handler = NextAuth({
      ...
    })
    
    async function auth(req, body) {
      const response = handler(req,body);
      const res = await response; // If you want to access the response object to modify
      return res;
    }
    
    export { auth as GET, auth as POST }
    

    I'm just not sure about the body parameter though, you'd have to read the NextJS docs, I'm assuming based on debbuging.