Setup Project#
GitHub this note show how to create a new nextjs project
npx create-next-app@latest .
install next-auth
npm install next-auth
Project structure
|--app|--globals.css|--layout.css|--page.tsx|--pages|--api|--auth|--[...nextauth].js|--public|--.env.local|--next.config.js|--package.json|--postcss.config.js|--tailwind.config.js|--tsconfig.json|--.eslintrc.json
let edit the [...nextauth].js to add cognito provider
import NextAuth from "next-auth";import GithubProvider from "next-auth/providers/github";import CognitoProvider from "next-auth/providers/cognito";export const authOptions = {// Configure one or more authentication providersproviders: [CognitoProvider({clientId: process.env.COGNITO_CLIENT_ID,clientSecret: process.env.COGNITO_CLIENT_SECRET,issuer: process.env.COGNITO_ISSUER,}),],secret: process.env.JWT_SECRET,};
please take note the cognito issuer format
https://cognito-idp.{region}.amazonaws.com/{PoolId}
finally we need to update the .env.local as
COGNITO_CLIENT_ID=COGNITO_CLIENT_SECRET=COGNITO_ISSUER=https://cognito-idp.{region}.amazonaws.com/{PoolId}NEXTAUTH_URL=http://localhost:3000JWT_SECRET=
Login Page#
In the NextJS 13, we can setup it in the RootLayout, and use SessionProvider to pass session of user as the following
"use client";import { SessionProvider } from "next-auth/react";import "./globals.css";export default function RootLayout({children,}: {children: React.ReactNode;}) {return (<html lang="en"><SessionProvider><body>{children}</body></SessionProvider></html>);}
The Log In page with login button which will trigger Provider as
"use client";import { signIn, signOut, useSession } from "next-auth/react";export default function Home() {const { data: session, status } = useSession();return (<main className="flex min-h-screen flex-col items-center max-w-5xl bg-slate-100 mx-auto justify-center space-y-20">{session?.user ? (<><h1 className="text-2xl">Hello {session.user.name} {session.user.email}{" "}</h1><buttonclassName="bg-orange-300 px-20 py-3 rounded-sm"onClick={() => signOut()}>Sign Out</button></>) : (<><h1 className="text-2xl">Please log in first</h1><buttontype="submit"className="bg-green-400 px-20 py-3 rounded-sm cursor-pointer"onClick={() =>signIn("cognito", {redirect: true,callbackUrl: "/",})}>Sign In</button></>)}</main>);}
Server Side#
Let create a protected page in /app/profile/page.tsx
- Get cookies or token from header request
- Verify the cookies or token, get user information
- Server render the responding page
import { cookies, headers } from "next/headers";import { decode } from "next-auth/jwt";const getUser = async () => {const authHeader = headers().get("authorization");const sessionToken = cookies().get("next-auth.session-token");const user = await decode({token: sessionToken?.value,secret: process.env.JWT_SECRET as string,});console.log("auth header ", authHeader);console.log("session token from cookies ", sessionToken);console.log("decode token ", user);return user;};const ProfilePage = async () => {const user = await getUser();if (user) {return (<div><h1>Hello {user.email} {user.name}{" "}</h1></div>);}return (<div><h1>Please log in first</h1></div>);};export default ProfilePage;