Search code examples
next.jsnext-auth

next-auth callbacks authorized never called


Using the following NextAuthConfig (with some areas redacted), I cannot get callbacks.authorized to fire.

It is mentioned in the official docs https://authjs.dev/reference/next-auth#authorized with some kind of dependency on middleware, though that does not seem clear to me. Any ideas?

const authOptions: NextAuthConfig = {
    trustHost: true,
    session: {
        strategy: 'jwt',
    },
    providers: [
        CredentialsProvider({
            id: 'mycompany',
            name: 'mycompany',
            type: 'credentials',
            authorize: authorize as any,
            credentials: {
                email: { label: 'Email', type: 'text', placeholder: '[email protected]' },
                password: { label: 'Password', type: 'password' },
            },
        }) as any,
    ],
    pages: {
        signIn: '/auth/signin',
    },
    callbacks: {
        async authorized({ auth, request: { nextUrl } }) {
            throw new Error('this never happens')
        },
        redirect: ({ baseUrl, url }: any) => {
            // snip (works)
        },
        async jwt({ token, ...params }: any) {
            // snip (works)
        },
        async session({ session, ...params }: any) {
            // snip (works)
        },
    }
}

export default authOptions
async function authorize(credentials?: { email?: string; password?: string }) {
 // snip (works)
}

middleware.ts

import { getSubdomainFromHost } from '@mycompany/shared/helpers/url';
import { NextResponse, type NextFetchEvent, type NextRequest } from 'next/server';
import { getLogger } from './lib/getLogger';

const logger = getLogger()

// export const config = {
//  matcher: [
//    /*
//     * Match all request paths except for the ones starting with:
//     * - api (API routes)
//     * - _next/static (static files)
//     * - _next/image (image optimization files)
//     * - favicon.ico (favicon file)
//     */
//    {
//      source: '/((?!_next/static|_next/image|favicon.ico|icons|logo).*)',
//      missing: [
//        { type: 'header', key: 'next-router-prefetch' },
//        { type: 'header', key: 'purpose', value: 'prefetch' },
//      ],
//    },
//  ],
// }

export function middleware(request: NextRequest, _next: NextFetchEvent) {
    const headers = new Headers(request.headers)
    headers.set('x-forwarded', request.url)
    headers.set('x-base-url', `${request.nextUrl.protocol}://${request.nextUrl.host}`)
    // const nextUrl = request.nextUrl
    const host = request.headers.get('host')
    // const pathname = nextUrl.pathname
    const subdomain = getSubdomainFromHost(host)
    if(subdomain) {
        headers.set('x-subdomain', subdomain)
    }

     

    logger.debug(`[Middleware] NextResponse.next: `, request.url)
    return NextResponse.next({
        request: {
            headers,
        },
    })
}

npm versions:

"next": "14.2.3",
"next-auth": "5.0.0-beta.17",

Solution

  • The callbacks.authorized is executed when you use auth as middleware to protect private pages, which is not the case here.

    Source code: https://github.com/nextauthjs/next-auth/blob/7a6c2d3f4d53612c317e4033e81d23cc10d7b035/packages/next-auth/src/lib/index.ts#L238

    export const middleware = auth((request) => {
        // `callbacks.authorized` will be called as part of the wrapper
        // You have access to request.auth
    
        const headers = new Headers(request.headers)
        headers.set('x-forwarded', request.url)
        // ...
    })