Introduction#
GitHub this shows how to setup nextauth with amplify hosting and your own domain
- nextjst and nextauth bare
- amplify hosting
- my own domain and auth
Setup Project#
let 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
Cognito Provider#
Let update [...nextauth].js in pages/api/auth/
import NextAuth from "next-auth";import CognitoProvider from "next-auth/providers/cognito";export const authOptions = {providers: [CognitoProvider({clientId: process.env.COGNITO_CLIENT_ID,clientSecret: process.env.COGNITO_CLIENT_SECRET,issuer: process.env.COGNITO_ISSUER,}),],secret: process.env.JWT_SECRET,pages: {},events: {async signOut(message) {console.log(message);},},session: {// seconds - how long until a idle session expiresmaxAge: 5 * 60,// seconds - how frequently to write to database to extend a sessionupdateAge: 60 * 60,//clientMaxAge: 5 * 60,//strategy: "jwt",},callbacks: {async signIn({ user, account, profile, email, credentials }) {return true;},async redirect({ url, baseUrl }) {return baseUrl;},async session({ session, user, token }) {try {session.id_token = token.id_token;} catch (error) {}return session;},async jwt({ token, user, account, profile, isNewUser }) {try {token.id_token = account.id_token;// console.log("callback jwt ", token);} catch (error) {}return token;},},};export default NextAuth(authOptions);
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 } = useSession();console.log(session);return (<main className="flex min-h-screen flex-col items-center justify-center space-y-5">{session?.user ? (<><h1>Hello {session.user.email}</h1><buttonclassName="bg-orange-300 px-20 py-3 rounded-sm"onClick={() => signOut()}>Sign Out</button></>) : (<><buttontype="submit"// disabledclassName="bg-green-400 px-20 py-3 rounded-sm cursor-pointer"onClick={() => signIn("cognito")}>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;
Cognito UserPool#
- create a cognito user pool
- create client with secret id
The allowed callback URLs look like this
https://en.entest.io/api/auth/callback/cognito
The cognito issuer
COGNITO_ISSUER=https://cognito-idp.us-east-1.amazonaws.com/${USER_POOL_ID}
The cognito user pool id
COGNITO_POOL_ID="cognito-idp.us-east-1.amazonaws.com/${USER_POOL_ID}"
Amplify Hosting#
- setup environmt variables
- setup building as below
Build setting
version: 1frontend:phases:preBuild:commands:- npm cibuild:commands:- echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env- echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env- echo "COGNITO_ISSUER=$COGNITO_ISSUER" >> .env- echo "COGNITO_CLIENT_SECRET=$COGNITO_CLIENT_SECRET" >> .env- echo "COGNITO_CLIENT_ID=$COGNITO_CLIENT_ID" >> .env- echo "JWT_SECRET=$JWT_SECRET" >> .env- npm run buildartifacts:baseDirectory: .nextfiles:- '**/*'cache:paths:- node_modules/**/*
Troubleshooting#
- delete the cache in build setting and rebuild
- wait a hour in case of deleting route 53 CNAME record