Search code examples
typescriptnext.jsnext-auth

how to implement next-auth for external API login in Next 13 appDir


Hi I am trying to implement a login with next-auth in next 13 has appDir: true and the version of next is 13.3.0 but I checked the documentation but the truth is I don't understand, I am doing it with typescript but there is almost no documentation and I don't know if I am doing it right.

app/api/auth/[...nextauth]/route.ts

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

const handler = NextAuth({
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        username: { label: "Username", type: "text" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials, req) {
        const { username, password } = credentials as { username: string; password: string };
        const res = await fetch("http://localhost:3000/api/auth/login", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ username, password }),
        });
        const user = await res.json();
        if (res.ok) {
          return user;
        } else {
          return null;
        }
      },
    }),
  ],
  session: {
    strategy: "jwt"
  },
});

export { handler as GET, handler as POST };

layout.tsx

'use client'

import './globals.css'
import { SessionProvider } from "next-auth/react"


export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <SessionProvider>
          {children}
        </SessionProvider>
      </body>
    </html>
  )
}

when I add the <SessionProvider>{children}</SessionProvider> I get the following error and it does not load the pages. enter image description here


Solution

  • app/api/auth/[... nextauth]/route.ts

    import NextAuth from "next-auth";
    import CredentialsProvider from "next-auth/providers/credentials";
    
    interface User {
      id: number;
      name: string;
      email: string;
      password: string;
      role: string;
      created_at: string;
      updated_at?: any;
      iat: number;
      exp: number;
      jti: string;
    }
    
    const handler = NextAuth({
      session: {
        strategy: "jwt",
      },
      providers: [
        CredentialsProvider({
          name: "Credentials",
          credentials: {
            email: { label: "Email", type: "text", placeholder: "jsmith" },
            password: { label: "Password", type: "password" },
          },
          async authorize(credentials) {
            const { email, password } = credentials as {
              email: string;
              password: string;
            };
            const res = await fetch("http://127.0.0.1:8000/login", {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
              },
              body: JSON.stringify({ email, password }),
            });
            // tipar peticion de user
            const user = await res.json();
            if (res.ok && user) {
              // mostrar el encabezado de autorización en la consola
              return user;
            } else {
              return null;
            }
          },
        }),
      ],
      callbacks: {
        jwt: async ({ token, user }) => {
          if (user) token = user as unknown as { [key: string]: any };
          console.log(token);
          
          return token;
        },
        session: async ({ session, token }) => {
          session.user = { ...token }
          return session;
        },
      },
      secret: "supersecret",
      pages: {
        signIn: "/login",
      },
    });
    
    export { handler as GET, handler as POST };
    

    enter image description here

    app/Providers.tsx

    'use client'
    
    import React, { ReactNode } from 'react';
    import { SessionProvider } from "next-auth/react"
    
    
    interface Props {
        children: ReactNode
    }
    
    function Providers({ children }: Props) {
      return <SessionProvider>{children}</SessionProvider>
    }
    
    export default Providers;
    

    layout.tsx

    import { ReactNode } from 'react'
    import './globals.css'
    import Provider from './Providers'
    
    interface Props {
      children: ReactNode
    }
    
    export default function RootLayout({ children }: Props) {
      return (
        <html lang="en">
          <head>
            <meta charSet="utf-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1" />
            <meta name="description" content="Generated by create next app" />
            <meta name="author" content="Vercel" />
            <link rel="stylesheet" href="https://cdn.lineicons.com/4.0/lineicons.css" />
          </head>
          <body>
            <Provider>{children}</Provider>
          </body>
        </html>
      )
    }
    

    and when sending the credentials, the same credentials and data are sent.