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 providers
providers: [
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:3000
JWT_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>
<button
className="bg-orange-300 px-20 py-3 rounded-sm"
onClick={() => signOut()}
>
Sign Out
</button>
</>
) : (
<>
<h1 className="text-2xl">Please log in first</h1>
<button
type="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;