DEV Community

Enmanuel Alfonzo Angulo
Enmanuel Alfonzo Angulo

Posted on

Next Auth Login Web3 with Next13

Primero creamos un projecto en Nextjs you utilizo yarn pero puedes elegir el que mas te guste

yarn create next-app
Enter fullscreen mode Exit fullscreen mode

en mi caso me gusta usar typescript pero puedes utilizar javascript si te es más cómodo
✔ Would you like to use TypeScript with this project? … No / Yes

Puedes crear tu project o con tus preferencias en este caso usaremos la carpeta experimental app, luego de que se instalen todas las dependencias corra el projecto

ahora vamos a agregar next auth

yarn add next-auth
Enter fullscreen mode Exit fullscreen mode

otras dependencias

yarn add siwe@beta ethers wagmi
Enter fullscreen mode Exit fullscreen mode

aqui vamos a usar algo feo debido a que aun no he visto otra manera de integrar nextAuth crearemos la carpeta al mismo nivel que la carpeta app pages/api/auth/[...nextauth].ts

ahora nuestro archivo debe verse así

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { getCsrfToken } from "next-auth/react";
import { SiweMessage } from "siwe";

// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default async function auth(req: any, res: any) {
  const providers = [
    CredentialsProvider({
      name: "Ethereum",
      credentials: {
        message: {
          label: "Message",
          type: "text",
          placeholder: "0x0",
        },
        signature: {
          label: "Signature",
          type: "text",
          placeholder: "0x0",
        },
      },
      async authorize(credentials) {
        try {
          const siwe = new SiweMessage(
            JSON.parse(credentials?.message || "{}")
          );
          const nextAuthUrl = new URL(process.env.NEXTAUTH_URL || "");

          const result = await siwe.verify({
            signature: credentials?.signature || "",
            domain: nextAuthUrl.host,
            nonce: await getCsrfToken({ req }),
          });

          if (result.success) {
            return {
              id: siwe.address,
            };
          }
          return null;
        } catch (e) {
          return null;
        }
      },
    }),
  ];

  const isDefaultSigninPage =
    req.method === "GET" && req.query.nextauth.includes("signin");

  // Hide Sign-In with Ethereum from default sign page
  if (isDefaultSigninPage) {
    providers.pop();
  }

  // eslint-disable-next-line no-return-await
  return await NextAuth(req, res, {
    // https://next-auth.js.org/configuration/providers/oauth
    providers,
    session: {
      strategy: "jwt",
    },
    secret: process.env.NEXTAUTH_SECRET,
    callbacks: {
      async session({ session, token }: { session: any; token: any }) {
        // eslint-disable-next-line no-param-reassign
        session.address = token.sub;
        // eslint-disable-next-line no-param-reassign
        session.user.name = token.sub;
        // eslint-disable-next-line no-param-reassign
        session.user.image = "https://www.fillmurray.com/128/128";
        return session;
      },
    },
  });
}

Enter fullscreen mode Exit fullscreen mode

creemos nuestras variables de entorno, ahora para la Create a NEXTAUTH_SECRET puedes usar el siguiente comando openssl rand -base64 32 pero yo te recomiendo usar el que te genera GENERATE-SECRET

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=clave generada 
Enter fullscreen mode Exit fullscreen mode

ahora creamos nuestra carpeta app y creamos una folder llamada container donde crearemos las siguientes files
wagmi.container.ts

import React from "react";
import { configureChains, createClient, WagmiConfig } from "wagmi";
import { mainnet, bsc, polygon, bscTestnet, goerli } from "wagmi/chains";
import { publicProvider } from "wagmi/providers/public";
import { InjectedConnector } from "wagmi/connectors/injected";

// Config
const { chains, provider } = configureChains(
  [mainnet, bsc, polygon, bscTestnet, goerli],
  [publicProvider()]
);

const client = createClient({
  autoConnect: true,
  connectors: [new InjectedConnector({ chains })],
  provider,
});

// Provider
const WagmiProvider: React.FC<{
  children: React.ReactNode;
}> = ({ children }) => {
  return <WagmiConfig client={client}>{children}</WagmiConfig>;
};

export default WagmiProvider;


Enter fullscreen mode Exit fullscreen mode

and
root.provider.ts

"use client";

import React from "react";
import { Session } from "next-auth";
import { SessionProvider } from "next-auth/react";
import WagmiProvider from "./wagmi.container";

// Root Provider
function RootProvider({
  children,
  session,
}: {
  children: React.ReactNode;
  // eslint-disable-next-line react/require-default-props
  session?: Session;
}) {
  return (
    <WagmiProvider>
      <SessionProvider session={session} refetchInterval={0}>
        {children}
      </SessionProvider>
    </WagmiProvider>
  );
}

export default RootProvider;

Enter fullscreen mode Exit fullscreen mode

creamos el middleware este archivo va al mismo nivel de la carpeta app

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { getToken } from "next-auth/jwt";

export async function middleware(req: NextRequest) {
  const session = await getToken({ req, secret: process.env.NEXTAUTH_SECRET });

  if (!session) {
    const requestedPage = req.nextUrl.pathname;
    const url = req.nextUrl.clone();
    url.pathname = `/`;
    url.search = `p=${requestedPage}`;
    return NextResponse.redirect(url);
  }

  return NextResponse.next();
}

// See "Matching Paths" below to learn more
export const config = {
  matcher: ["/home", ""], // array con todas las routas que quieres proteger
};

Enter fullscreen mode Exit fullscreen mode

en este projecto uso tailwind pero puedes usar la liberia que te guste

este es el componente para realizar el login

   <button
          // lassName="h-10 bg-blue-600 text-white px-6 rounded-full hover:bg-blue-800 transition-colors ease-in-out duration-200"
            type="button"
            onClick={(e) => {
              e.preventDefault();
              if (!isConnected) {
                connect();
              } else {
                handleLogin();
              }
            }}
          >
            Connect Wallet
          </button>
Enter fullscreen mode Exit fullscreen mode

en la app creamos un page app/home/page.tsx


import React from "react";
import { useSession } from "next-auth/react";
import { useDisconnect } from "wagmi";
import { signOut } from "next-auth/react";

function Home() {
  const { data: session } = useSession();
  const address = session?.user?.email ?? session?.user?.name;
  const { disconnect } = useDisconnect();
  const callbackUrl = "/";
  return (
    <div>
      <p>{address}</p>
<button
            type="button"
            onClick={(e) => {
              e.preventDefault();
              disconnect();
              signOut({
                redirect: true,
                callbackUrl,
              });
            }}
          >
            Disconnect Wallet
          </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

hasta aqui tienes las bases para crear tu primera Dapp seguire subiendo tutoriales de como intreracturar con contratos y como crear tu propios smart contracts

Top comments (0)