Our front-end authentication solution uses NextAuth.js version "^4.24.4" but, NextAuth.js version 5, now called Auth.js, is a major rewrite of the next-auth package. Auth.js aims to improve and streamline authentication using standard Web APIs and single method authentication setup while introducing as few breaking changes as possible. See migrating-to-v5
New account() callback on providers (account() docs)
p- Edge-compatible
Universal auth(): A single method to authenticate anywhere using auth() instead of getServerSession, getSession, withAuth, getToken, and useSession (Read more)
Migration Steps
[x] upgrade to latest next-auth@beta
[x] upgrade to latest next.js
[x] create a root level auth folder
[x] create auth\auth.config.ts file that can be imported where required
[x] create auth\index.ts file making call to NextAuth and export all the returned objects
[x] import handlers from @/auth into app/api/auth/[...nextauth]/route.ts
[x] change reading the session in Server Components from getServerSession(authoptions) function to auth() function
[x] modify client/app/api/auth/token/route.ts to use import { getToken } from "@auth/core/jwt";Noteauthentication methods indicate API Route getToken(req)=auth(req, res) but, the auth returned is the return value of session() callback not the return value of jwt(), the encoded token stored in server side cookie that contains user guid information. Used import { getToken } from "@auth/core/jwt"; instead.
[x] import client/app/api/auth/token/route.ts to use in client/middleware.ts
Steps to create auth v5 JWT tokens for GitHub secrets
[ ] for each role, save the JWT token payload obtained from Keycloak\NextAuth authentication
[ ] modify client/auth/index.ts\session\maxAge to hard-coded maxAge: 946080000, so to set the expiration of the JWT to 30 years
[ ] use Playwright codegen from terminal command from cd client to save the NextAuth JWT object created after Keycloak login as a storageState file:
[ ] login with bc-cas-dev with role industry_user_admin using command npx playwright codegen http://localhost:3000 --save-storage=industry_user_admin.json
[ ] close the playwright codegen window and validate the file has been created client\industry_user_admin.json
[ ] login with bc-cas-dev-secondary with role industry_user using command npx playwright codegen http://localhost:3000 --save-storage=industry_user.json
[ ] close the playwright codegen window and validate the file has been created client\industry_user.json
[ ] login with bc-cas-dev-three with no role using command npx playwright codegen http://localhost:3000 --save-storage=new_user.json
[ ] close the playwright codegen window and validate the file has been created client\new_user.json
[ ] modify client/auth/auth.config.ts\callbacks\async jwt to hard-code the token.app_role for each required cas role
[ ] for hard coded token.app_role="cas_admin"; return token; login with your IDIR ID using command npx playwright codegen http://localhost:3000 --save-storage=cas_admin.json
[ ] close the playwright codegen window and validate the file has been created client\cas_admin.json
[ ] for hard coded token.app_role="cas_analyst"; return token; login with your IDIR ID using command npx playwright codegen http://localhost:3000 --save-storage=cas_analyst.json
[ ] close the playwright codegen window and validate the file has been created client\cas_analyst.json
[ ] for hard coded token.app_role="cas_pending"; return token; login with your IDIR ID using command npx playwright codegen http://localhost:3000 --save-storage=cas_pending.json
[ ] close the playwright codegen window and validate the file has been created client\cas_pending.json
[ ] modify client/app/api/auth/[...nextauth]/route.ts\callbacks\async jwt REMOVING hard-code the token.app_role
[ ] modify client/app/api/auth/[...nextauth]/route.ts\session\maxAge to maxAge: 30 * 60, // 30 minutes matching Keycloak token expiration time
[ ] modify all the saved storageState files object's expires properties to -1 "expires": -1
[ ] save the storageState file JSON objects to client/e2e/.env.local/E2E_*role*_STORAGE_STATE
[ ] save E2E_*role*_STORAGE_STATE JSON objects in client/e2e/.env.local to 1password OBPS FE E2E STORAGESTATES AUTH v5
[ ] stringify the storageState file JSON objects (i.e. using javascript: console.log(JSON.stringify({JSON OBJECT GOES HERE}))
[ ] save the stringify JSON object in a GitHub secret(s) reflecting the E2E_*role*_STORAGE_STATE name
Note Not changing the .env vars to follow AUTH_ naming convention
There are no breaking changes to the environment variables, but some new best practices have been implemented for environment variables.
All environment variables should be prefixed with AUTH_, NEXTAUTH_ is no longer in use.
If you name your provider secret / clientId variables using this syntax, i.e. AUTH_GITHUB_SECRET and AUTH_GITHUB_ID, they will be auto-detected and you won’t have to explicitly pass them into your provider’s configuration.
The NEXTAUTH_URL/AUTH_URL is not strictly necessary anymore in most environments. We will auto-detect the host based on the request headers.
The AUTH_TRUST_HOST environment variable serves the same purpose as setting trustHost: true in your Auth.js configuration. This is necessary when running Auth.js behind a proxy. When set to true we will trust the X-Forwarded-Host and X-Forwarded-Proto headers passed to the app by the proxy to auto-detect the host URL (AUTH_URL)
The AUTH_SECRET environment variable is the only variable that is really necessary. You do not need to additionally pass this value into your config as the secret configuration option if you’ve set the environment variable.
- NEXTAUTH_SECRET=AUTH_SECRET
- KEYCLOAK_CLIENT_ID=AUTH_KEYCLOAK_CLIENT_ID
- KEYCLOAK_CLIENT_SECRET=AUTH_KEYCLOAK_CLIENT_SECRET
- KEYCLOAK_LOGIN_URL=AUTH_KEYCLOAK_ISSUER
Tech Debt Triage
Risk Value Scoring:
Level
Value
High
3
Medium
2
Low
1
Technical Debt - Risk Types
Level
Value
Business Area Risk - Risk of business area visibility / damage to user experience
Developer Fault Risk - How likely will this tech debt cause a future error related to coding on top of it
System Fault Risk - Risk of system errors or application downtime
Time Scale Risk - Compound risk effect if left alone. How much more difficult to fix or dangerous will this become over time?
Time Sink Risk - How much will this tech debt slow the development process down
Description of the Tech Debt
Our front-end authentication solution uses NextAuth.js version "^4.24.4" but, NextAuth.js version 5, now called Auth.js, is a major rewrite of the next-auth package. Auth.js aims to improve and streamline authentication using standard Web APIs and single method authentication setup while introducing as few breaking changes as possible. See migrating-to-v5
New Features
Migration Steps
next-auth@beta
next.js
auth
folderauth\auth.config.ts
file that can be imported where requiredauth\index.ts
file making call to NextAuth and export all the returned objects@/auth
intoapp/api/auth/[...nextauth]/route.ts
getServerSession(authoptions)
function toauth()
functionclient/app/api/auth/token/route.ts
to useimport { getToken } from "@auth/core/jwt";
Note authentication methods indicateAPI Route getToken(req)=auth(req, res)
but, theauth
returned is the return value of session() callback not the return value of jwt(), the encoded token stored in server side cookie that contains user guid information. Usedimport { getToken } from "@auth/core/jwt";
instead.client/app/api/auth/token/route.ts
to use inclient/middleware.ts
Steps to create auth v5 JWT tokens for GitHub secrets
client/auth/index.ts\session\maxAge
to hard-codedmaxAge: 946080000,
so to set the expiration of the JWT to 30 yearscd client
to save the NextAuth JWT object created after Keycloak login as a storageState file:bc-cas-dev
with roleindustry_user_admin
using commandnpx playwright codegen http://localhost:3000 --save-storage=industry_user_admin.json
client\industry_user_admin.json
bc-cas-dev-secondary
with roleindustry_user
using commandnpx playwright codegen http://localhost:3000 --save-storage=industry_user.json
client\industry_user.json
bc-cas-dev-three
with no role using commandnpx playwright codegen http://localhost:3000 --save-storage=new_user.json
client\new_user.json
client/auth/auth.config.ts\callbacks\async jwt
to hard-code thetoken.app_role
for each required cas roletoken.app_role="cas_admin"; return token;
login with your IDIR ID using commandnpx playwright codegen http://localhost:3000 --save-storage=cas_admin.json
client\cas_admin.json
token.app_role="cas_analyst"; return token;
login with your IDIR ID using commandnpx playwright codegen http://localhost:3000 --save-storage=cas_analyst.json
client\cas_analyst.json
token.app_role="cas_pending"; return token;
login with your IDIR ID using commandnpx playwright codegen http://localhost:3000 --save-storage=cas_pending.json
client\cas_pending.json
client/app/api/auth/[...nextauth]/route.ts\callbacks\async jwt
REMOVING hard-code thetoken.app_role
client/app/api/auth/[...nextauth]/route.ts\session\maxAge
to maxAge: 30 * 60, // 30 minutes matching Keycloak token expiration time"expires": -1
client/e2e/.env.local/E2E_*role*_STORAGE_STATE
E2E_*role*_STORAGE_STATE
JSON objects inclient/e2e/.env.local
to 1passwordOBPS FE E2E STORAGESTATES AUTH v5
E2E_*role*_STORAGE_STATE
nameNote Not changing the .env vars to follow
AUTH_
naming conventionTech Debt Triage
Risk Value Scoring: