hoangvvo / next-connect

The TypeScript-ready, minimal router and middleware layer for Next.js, Micro, Vercel, or Node.js http/http2

Home Page:https://www.npmjs.com/package/next-connect

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to implement passport with next-connect in Next 14?

RicardoNRevs opened this issue · comments

Hi everyone.
Previously, I've followed this example project https://github.com/vercel/next.js/tree/canary/examples/with-passport-and-next-connect to connect an external SSO with my app and works with this passport configuration without any problem

lib/passport.ts
const __CALLBACK__ = process.env.CALLBACK_URL
const __ENTRY_POINT__ = process.env.ENTRY_POINT
const __ISSUER__ = process.env.ISSUER
const __CERTIFICATE__ = process.env.CERTIFICATE

passport.serializeUser((user, cb) => {
    process.nextTick(function () {
        return cb(null, user);
    });
});
  

passport.deserializeUser(function (req, id, done) {
  // deserialize the username back into user object
  process.nextTick(function () {
    return cb(null, user);
  });
});

passport.use(
    new SAMLStrategy(
        {
            callbackUrl: __CALLBACK__,
            entryPoint: __ENTRY_POINT__,
            issuer: __ISSUER__,
            cert: __CERTIFICATE__
        },
        (profile, done) => {
            return saveUser(profile);
        }
    )
);

const saveUser = (user) => {
    return new Promise((resolve, reject) => {
      resolve("Successful");
    });
};

export default passport;

then I call it in the login API like this

import passport from "@/lib/passport";

const handler = nextConnect();

handler.use(passport .initialize()).get(passport.authenticate("saml"),{});

export default handler;

All this work with "next-connect": "^0.6.1", "passport": "^0.4.1", "passport-saml": "^3.2.4"

Now I'm trying to replicate that in NextJS v14 with "next-connect": "^1.0.0-next.3" but I got the following issue

Error: No response is returned from route handler 'C:\dummy\nextjs-portal-v1\src\app\api\login\route.ts'. Ensure you return a `Response` or a `NextResponse` in all branches of your handler.
    at C:\dummy\nextjs-portal-v1\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:63974
    at async eU.execute (C:\dummy\nextjs-portal-v1\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:53964)
    at async eU.handle (C:\dummy\nextjs-portal-v1\node_modules\next\dist\compiled\next-server\app-route.runtime.dev.js:6:65062)
    at async doRender (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\base-server.js:1333:42)
    at async cacheEntry.responseCache.get.routeKind (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\base-server.js:1555:28)
    at async DevServer.renderToResponseWithComponentsImpl (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\base-server.js:1463:28)
    at async DevServer.renderPageComponent (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\base-server.js:1856:24)
    at async DevServer.renderToResponseImpl (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\base-server.js:1894:32)
    at async DevServer.pipeImpl (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\base-server.js:911:25)
    at async NextNodeServer.handleCatchallRenderRequest (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\next-server.js:271:17)
    at async DevServer.handleRequestImpl (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\base-server.js:807:17)
    at async C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\dev\next-dev-server.js:331:20
    at async Span.traceAsyncFn (C:\dummy\nextjs-portal-v1\node_modules\next\dist\trace\trace.js:151:20)
    at async DevServer.handleRequest (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\dev\next-dev-server.js:328:24)
    at async invokeRender (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\lib\router-server.js:163:21)
    at async handleRequest (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\lib\router-server.js:342:24)
    at async requestHandlerImpl (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\lib\router-server.js:366:13)
    at async Server.requestListener (C:\dummy\nextjs-portal-v1\node_modules\next\dist\server\lib\start-server.js:140:13)

This is the api/login/route.ts file

import { createEdgeRouter } from "next-connect";
import type { NextRequest, NextResponse } from "next/server";

import passport from "@/lib/passport";

const router = createEdgeRouter<NextRequest, { params?: unknown }>();

router.use(passport.initialize() as any)
    .get(
        passport.authenticate("saml", {
            failureRedirect: "/",})
    );

export async function GET(request: NextRequest, ctx: { params?: unknown }) {
    return router.run(request, ctx) as Promise<NextResponse>;
}
      

The @/lib/passport it's almost the same as before

import passport from "passport";
import { Strategy as SAMLStrategy, Profile } from "passport-saml";


const __CALLBACK__ = process.env.CALLBACK_URL
const __ENTRY_POINT__ = process.env.ENTRY_POINT
const __ISSUER__ = process.env.ISSUER
const __CERTIFICATE__ = process.env.CERTIFICATE

passport.serializeUser((user: any, done) => {
    done(null, user);
});

passport.deserializeUser((user: any, done) => {
    done(null, user);
})

passport.use(
    new SAMLStrategy(
    {
        callbackUrl: __CALLBACK__,
        entryPoint: __ENTRY_POINT__,
        issuer: __ISSUER__,
        cert: __CERTIFICATE__ || ''
    }, (profile: Profile | null | undefined, done: (err: Error | null, user?: any) => void) => {
        if (profile) {
            return done(null, profile);
        } else {
            return done(new Error("Invalid profile"));
        }
    })
);
      

export default passport;

Did I miss something when I'm calling the passport implementation?
Thanks for your help