From e93e43e16d0c21ad2974cf79aa9190236c28cea6 Mon Sep 17 00:00:00 2001 From: theexiile1305 Date: Mon, 29 Apr 2024 12:48:31 +0200 Subject: [PATCH 1/6] feat: next-auth upgrade to 5 --- README.md | 5 +- __tests__/app/errorDescription.test.ts | 62 +-------- __tests__/app/not-found.test.tsx | 2 +- __tests__/app/page.test.tsx | 10 +- .../app/ui/__snapshots__/navbar.test.tsx.snap | 4 +- .../__snapshots__/signInButton.test.tsx.snap | 15 ++- .../__snapshots__/signOutButton.test.tsx.snap | 15 ++- __tests__/app/ui/authErrorView.test.tsx | 2 +- __tests__/app/ui/navbar.test.tsx | 10 +- __tests__/app/ui/signInButton.test.tsx | 38 ++---- __tests__/app/ui/signOutButton.test.tsx | 38 ++---- .../{app/authOptions.test.ts => auth.test.ts} | 62 ++++----- __tests__/config/defineConfig.test.ts | 7 +- app/api/auth/[...nextauth]/route.ts | 7 +- app/errorDescription.ts | 20 +-- app/page.tsx | 5 +- app/ui/navbar.tsx | 5 +- app/ui/signInButton.tsx | 19 ++- app/ui/signOutButton.tsx | 17 +-- app/authOptions.ts => auth.ts | 19 ++- config/defineConfig.ts | 4 +- config/type.ts | 2 - package.json | 2 +- pnpm-lock.yaml | 121 +++++++++--------- tsconfig.json | 8 +- types/next-auth.d.ts | 20 +-- 26 files changed, 197 insertions(+), 322 deletions(-) rename __tests__/{app/authOptions.test.ts => auth.test.ts} (57%) rename app/authOptions.ts => auth.ts (68%) diff --git a/README.md b/README.md index e7e06ebb..499b1154 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,8 @@ Create a file called `.env.local` in the root of the project and add the followi ```bash # next-auth environment variables -NEXTAUTH_DEBUG="" -NEXTAUTH_SECRET="" -NEXTAUTH_URL="" +AUTH_DEBUG="" +AUTH_SECRET="" # generate a secret using `pnpm exec auth secret` # shibboleth oidc environment variables SHIBBOLETH_OIDC_ISSUER_URL="" diff --git a/__tests__/app/errorDescription.test.ts b/__tests__/app/errorDescription.test.ts index fa708123..3be939dd 100644 --- a/__tests__/app/errorDescription.test.ts +++ b/__tests__/app/errorDescription.test.ts @@ -2,60 +2,6 @@ import { describe, it, expect } from 'vitest'; import { getAuthErrorDescription } from '@/app/errorDescription'; describe('errorDescription', () => { - it('OAuthSignin should return value', () => { - expect(getAuthErrorDescription('OAuthSignin')).toEqual( - 'Error in constructing an authorization URL.', - ); - }); - - it('OAuthCallback should return value', () => { - expect(getAuthErrorDescription('OAuthCallback')).toEqual( - 'Error in handling the response from an OAuth provider.', - ); - }); - - it('OAuthCreateAccount should return value', () => { - expect(getAuthErrorDescription('OAuthCreateAccount')).toEqual( - 'Could not create OAuth provider user in the database.', - ); - }); - - it('EmailCreateAccount should return value', () => { - expect(getAuthErrorDescription('EmailCreateAccount')).toEqual( - 'Could not create email provider user in the database.', - ); - }); - - it('Callback should return value', () => { - expect(getAuthErrorDescription('Callback')).toEqual( - 'Error in the OAuth callback handler route.', - ); - }); - - it('OAuthAccountNotLinked should return value', () => { - expect(getAuthErrorDescription('OAuthAccountNotLinked')).toEqual( - 'If the email on the account is already linked, but not with this OAuth account.', - ); - }); - - it('EmailSignin should return value', () => { - expect(getAuthErrorDescription('EmailSignin')).toEqual( - 'Sending the e-mail with the verification token failed.', - ); - }); - - it('CredentialsSignin should return value', () => { - expect(getAuthErrorDescription('CredentialsSignin')).toEqual( - "The authorize callback returned null in the Credentials provider. We don't recommend providing information about which part of the credentials were wrong, as it might be abused by malicious hackers.", - ); - }); - - it('SessionRequired should return value', () => { - expect(getAuthErrorDescription('SessionRequired')).toEqual( - 'The content of this page requires you to be signed in at all times. See useSession for configuration.', - ); - }); - it('Configuration should return value', () => { expect(getAuthErrorDescription('Configuration')).toEqual( 'There is a problem with the server configuration. Check if your options are correct.', @@ -74,15 +20,15 @@ describe('errorDescription', () => { ); }); - it('default should return value', () => { - expect(getAuthErrorDescription('')).toEqual( - 'Catch all, will apply, if none of the other errors matched.', + it('Default should return value', () => { + expect(getAuthErrorDescription('EmailCreateAccount')).toEqual( + 'Catch all, will apply, if none of the above matched.', ); }); it('default should return value', () => { expect(getAuthErrorDescription(null)).toEqual( - 'Catch all, will apply, if none of the other errors matched.', + 'Catch all, will apply, if none of the above matched.', ); }); }); diff --git a/__tests__/app/not-found.test.tsx b/__tests__/app/not-found.test.tsx index 3d5fa932..ae00daa6 100644 --- a/__tests__/app/not-found.test.tsx +++ b/__tests__/app/not-found.test.tsx @@ -4,7 +4,7 @@ import { cleanup, render, screen } from '@testing-library/react'; describe('NotFound', () => { beforeEach(() => { - render(NotFound()); + render(); }); it('should exists', () => { diff --git a/__tests__/app/page.test.tsx b/__tests__/app/page.test.tsx index e1ac5af3..5e3923e9 100644 --- a/__tests__/app/page.test.tsx +++ b/__tests__/app/page.test.tsx @@ -1,15 +1,15 @@ import { afterEach, beforeEach, describe, expect, it, Mock, vi } from 'vitest'; import { cleanup, render, screen } from '@testing-library/react'; import Page from '../../app/page'; -import { getServerSession } from 'next-auth'; +import { auth } from '@/auth'; -vi.mock('next-auth', () => ({ - getServerSession: vi.fn(), +vi.mock('@/auth', () => ({ + auth: vi.fn(), })); describe('Home, when user is not authenticated', () => { beforeEach(async () => { - (getServerSession as Mock).mockReturnValue(null); + (auth as Mock).mockReturnValue(null); render(await Page()); }); @@ -44,7 +44,7 @@ describe('Home, when user is authenticated', () => { }; beforeEach(async () => { - (getServerSession as Mock).mockReturnValue(Promise.resolve(session)); + (auth as Mock).mockReturnValue(Promise.resolve(session)); render(await Page()); }); diff --git a/__tests__/app/ui/__snapshots__/navbar.test.tsx.snap b/__tests__/app/ui/__snapshots__/navbar.test.tsx.snap index 8a326cc8..b2ab43d2 100644 --- a/__tests__/app/ui/__snapshots__/navbar.test.tsx.snap +++ b/__tests__/app/ui/__snapshots__/navbar.test.tsx.snap @@ -4,7 +4,7 @@ exports[`Navbar, when user is authenticated > Button should match snapshot 1`] = +`; + +exports[`SignInButton 1`] = ` + +`; + +exports[`SignOutButton 1`] = ` + +
+ +
); }; diff --git a/app/ui/signOutButton.tsx b/app/ui/signOutButton.tsx index 29d72f62..64ec42d7 100644 --- a/app/ui/signOutButton.tsx +++ b/app/ui/signOutButton.tsx @@ -1,17 +1,18 @@ -'use client'; - import { Button } from '@mui/material'; -import { signOut } from 'next-auth/react'; +import { signOut } from '@/auth'; const SignOutButton = () => { - const handleSignOut = () => { - signOut().catch((error) => console.error(`signOut error: ${error}`)); + const handleSignOut = async () => { + 'use server'; + await signOut(); }; return ( - +
+ +
); }; diff --git a/app/authOptions.ts b/auth.ts similarity index 68% rename from app/authOptions.ts rename to auth.ts index 526a5113..ad8baf75 100644 --- a/app/authOptions.ts +++ b/auth.ts @@ -1,22 +1,18 @@ import { appConfig } from '@/config'; -import { Awaitable, NextAuthOptions, User } from 'next-auth'; +import NextAuth, { NextAuthConfig } from 'next-auth'; -const authOptions: NextAuthOptions = { - secret: appConfig.nextAuth.secret, +export const config = { debug: appConfig.nextAuth.debug, providers: [ { id: 'shibboleth', name: 'Shibboleth', - type: 'oauth', - idToken: true, - checks: ['pkce', 'state'], + type: 'oidc', issuer: appConfig.shibboleth.issuerUrl, - wellKnown: `${appConfig.shibboleth.issuerUrl}/.well-known/openid-configuration`, - authorization: { params: { scope: appConfig.shibboleth.scope } }, clientId: appConfig.shibboleth.clientId, clientSecret: appConfig.shibboleth.clientSecret, - profile(profile): Awaitable { + authorization: { params: { scope: appConfig.shibboleth.scope } }, + profile(profile) { return { id: profile.sub, pairwiseId: profile.sub, @@ -33,12 +29,13 @@ const authOptions: NextAuthOptions = { }, async session({ session, token }) { session.user = { + ...session.user, id: token.sub, pairwiseId: token.pairwiseId, }; return session; }, }, -}; +} satisfies NextAuthConfig; -export default authOptions; +export const { auth, handlers, signIn, signOut } = NextAuth(config); diff --git a/config/defineConfig.ts b/config/defineConfig.ts index a948511f..c8edf982 100644 --- a/config/defineConfig.ts +++ b/config/defineConfig.ts @@ -3,9 +3,7 @@ import { AppConfig } from './type'; export const defineConfig = (): AppConfig => { return { nextAuth: { - debug: loadBoolean(process.env.NEXTAUTH_DEBUG), - secret: loadString(process.env.NEXTAUTH_SECRET), - url: loadString(process.env.NEXTAUTH_URL), + debug: loadBoolean(process.env.AUTH_DEBUG), }, shibboleth: { issuerUrl: loadString(process.env.SHIBBOLETH_OIDC_ISSUER_URL), diff --git a/config/type.ts b/config/type.ts index 6659d2ab..8d8666a2 100644 --- a/config/type.ts +++ b/config/type.ts @@ -5,8 +5,6 @@ export type AppConfig = { export type NextAuth = { debug: boolean; - url: string; - secret: string; }; export type Shibboleth = { diff --git a/package.json b/package.json index 6ba5346b..dd8f3e33 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "eslint": "8.57.0", "eslint-config-next": "14.2.3", "next": "14.2.3", - "next-auth": "^4.24.7", + "next-auth": "5.0.0-beta.17", "react": "18.3.1", "react-dom": "18.3.1", "typescript": "5.4.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7c6849d..3a8c5fdd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,8 +48,8 @@ importers: specifier: 14.2.3 version: 14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-auth: - specifier: ^4.24.7 - version: 4.24.7(next@14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 5.0.0-beta.17 + version: 5.0.0-beta.17(next@14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -101,6 +101,20 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@auth/core@0.30.0': + resolution: {integrity: sha512-8AE4m/nk+4EIiVCJwxZAsJeAQuzpEC8M8768mmKVn60CGDdupKQkVhxbRlm5Qh7eNRCoFFME+0DvtaX2aXrYaA==} + peerDependencies: + '@simplewebauthn/browser': ^9.0.1 + '@simplewebauthn/server': ^9.0.2 + nodemailer: ^6.8.0 + peerDependenciesMeta: + '@simplewebauthn/browser': + optional: true + '@simplewebauthn/server': + optional: true + nodemailer: + optional: true + '@babel/code-frame@7.24.2': resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} engines: {node: '>=6.9.0'} @@ -798,6 +812,9 @@ packages: '@types/babel__traverse@7.20.5': resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -1083,8 +1100,8 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie@0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} cosmiconfig@7.1.0: @@ -1719,8 +1736,8 @@ packages: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} - jose@4.15.5: - resolution: {integrity: sha512-jc7BFxgKPKi94uOvEmzlSWFFe2+vASyXaKUpdQKatWAESU2MWjDfFf0fdfc83CDKcA5QecabZeNLyfhe3yKNkg==} + jose@5.2.4: + resolution: {integrity: sha512-6ScbIk2WWCeXkmzF6bRPmEuaqy1m8SbsRFMa/FLrSCkGIhj8OLVG/IH+XHVmNMx/KUo8cVWEE6oKR4dJ+S0Rkg==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1886,14 +1903,19 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next-auth@4.24.7: - resolution: {integrity: sha512-iChjE8ov/1K/z98gdKbn2Jw+2vLgJtVV39X+rCP5SGnVQuco7QOr19FRNGMIrD8d3LYhHWV9j9sKLzq1aDWWQQ==} + next-auth@5.0.0-beta.17: + resolution: {integrity: sha512-XA/7JtAjOgDfAeotJPFUsFZGGItZwzZrxLt9Gc9fE7EchLk6zydZfuZ22Vvwixs3IilkN644D5IoD5tEOAFGCQ==} peerDependencies: - next: ^12.2.5 || ^13 || ^14 + '@simplewebauthn/browser': ^9.0.1 + '@simplewebauthn/server': ^9.0.2 + next: ^14 nodemailer: ^6.6.5 - react: ^17.0.2 || ^18 - react-dom: ^17.0.2 || ^18 + react: ^18.2.0 peerDependenciesMeta: + '@simplewebauthn/browser': + optional: true + '@simplewebauthn/server': + optional: true nodemailer: optional: true @@ -1925,17 +1947,13 @@ packages: nwsapi@2.2.7: resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} - oauth@0.9.15: - resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==} + oauth4webapi@2.10.4: + resolution: {integrity: sha512-DSoj8QoChzOCQlJkRmYxAJCIpnXFW32R0Uq7avyghIeB6iJq0XAblOD7pcq3mx4WEBDwMuKr0Y1qveCBleG2Xw==} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - object-hash@2.2.0: - resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} - engines: {node: '>= 6'} - object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} @@ -1967,10 +1985,6 @@ packages: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} - oidc-token-hash@5.0.3: - resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==} - engines: {node: ^10.13.0 || >=12.0.0} - once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -1978,9 +1992,6 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} - openid-client@5.6.5: - resolution: {integrity: sha512-5P4qO9nGJzB5PI0LFlhj4Dzg3m4odt0qsJTfyEtZyOlkgpILwEioOhVVJOrS1iVH494S4Ee5OCjjg6Bf5WOj3w==} - optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} @@ -2073,13 +2084,13 @@ packages: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} - preact-render-to-string@5.2.6: - resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==} + preact-render-to-string@5.2.3: + resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==} peerDependencies: preact: '>=10' - preact@10.20.1: - resolution: {integrity: sha512-JIFjgFg9B2qnOoGiYMVBtrcFxHqn+dNXbq76bVmcaHYJFYR4lW67AOcXgAYQQTDYXDOg/kTZrKPNCdRgJ2UJmw==} + preact@10.11.3: + resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -2468,10 +2479,6 @@ packages: url-parse@1.5.10: resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - vite-node@1.5.2: resolution: {integrity: sha512-Y8p91kz9zU+bWtF7HGt6DVw2JbhyuB2RlZix3FPYAYmUyZ3n7iTp8eSyLyY6sxtPegvxQtmlTMhfPhUfCUF93A==} engines: {node: ^18.0.0 || >=20.0.0} @@ -2640,6 +2647,16 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + '@auth/core@0.30.0': + dependencies: + '@panva/hkdf': 1.1.1 + '@types/cookie': 0.6.0 + cookie: 0.6.0 + jose: 5.2.4 + oauth4webapi: 2.10.4 + preact: 10.11.3 + preact-render-to-string: 5.2.3(preact@10.11.3) + '@babel/code-frame@7.24.2': dependencies: '@babel/highlight': 7.24.2 @@ -3276,6 +3293,8 @@ snapshots: dependencies: '@babel/types': 7.24.0 + '@types/cookie@0.6.0': {} + '@types/estree@1.0.5': {} '@types/json5@0.0.29': {} @@ -3626,7 +3645,7 @@ snapshots: convert-source-map@2.0.0: {} - cookie@0.5.0: {} + cookie@0.6.0: {} cosmiconfig@7.1.0: dependencies: @@ -4431,7 +4450,7 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jose@4.15.5: {} + jose@5.2.4: {} js-tokens@4.0.0: {} @@ -4594,20 +4613,11 @@ snapshots: natural-compare@1.4.0: {} - next-auth@4.24.7(next@14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next-auth@5.0.0-beta.17(next@14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): dependencies: - '@babel/runtime': 7.24.4 - '@panva/hkdf': 1.1.1 - cookie: 0.5.0 - jose: 4.15.5 + '@auth/core': 0.30.0 next: 14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - oauth: 0.9.15 - openid-client: 5.6.5 - preact: 10.20.1 - preact-render-to-string: 5.2.6(preact@10.20.1) react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - uuid: 8.3.2 next@14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -4643,12 +4653,10 @@ snapshots: nwsapi@2.2.7: {} - oauth@0.9.15: {} + oauth4webapi@2.10.4: {} object-assign@4.1.1: {} - object-hash@2.2.0: {} - object-inspect@1.13.1: {} object-keys@1.1.1: {} @@ -4691,8 +4699,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 - oidc-token-hash@5.0.3: {} - once@1.4.0: dependencies: wrappy: 1.0.2 @@ -4701,13 +4707,6 @@ snapshots: dependencies: mimic-fn: 4.0.0 - openid-client@5.6.5: - dependencies: - jose: 4.15.5 - lru-cache: 6.0.0 - object-hash: 2.2.0 - oidc-token-hash: 5.0.3 - optionator@0.9.3: dependencies: '@aashutoshrathi/word-wrap': 1.2.6 @@ -4797,12 +4796,12 @@ snapshots: picocolors: 1.0.0 source-map-js: 1.2.0 - preact-render-to-string@5.2.6(preact@10.20.1): + preact-render-to-string@5.2.3(preact@10.11.3): dependencies: - preact: 10.20.1 + preact: 10.11.3 pretty-format: 3.8.0 - preact@10.20.1: {} + preact@10.11.3: {} prelude-ls@1.2.1: {} @@ -5215,8 +5214,6 @@ snapshots: querystringify: 2.2.0 requires-port: 1.0.0 - uuid@8.3.2: {} - vite-node@1.5.2(@types/node@20.12.7): dependencies: cac: 6.7.14 diff --git a/tsconfig.json b/tsconfig.json index 23ba4fd5..f90ff64f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,12 @@ "@/*": ["./*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "types/next-auth.d.ts" + ], "exclude": ["node_modules"] } diff --git a/types/next-auth.d.ts b/types/next-auth.d.ts index 786f7ff9..e557e692 100644 --- a/types/next-auth.d.ts +++ b/types/next-auth.d.ts @@ -1,28 +1,12 @@ +import NextAuth from 'next-auth'; + declare module 'next-auth' { interface Session { user: User; } interface User { - id: string | undefined; - pairwiseId: string; - } -} - -declare module 'next-auth/jwt' { - interface JWT { id: string; pairwiseId: string; } } - -export interface ShibbolethProfile extends Record { - atHash: string; - sub: string; - aud: string; - authTime: number; - iss: string; - exp: number; - iat: number; - sid: string; -} From 8b191adc686abf0fc980634bc0cd9113e1f03fc7 Mon Sep 17 00:00:00 2001 From: theexiile1305 Date: Sat, 4 May 2024 16:57:19 +0200 Subject: [PATCH 2/6] feat: better type decoration --- types/next-auth.d.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/types/next-auth.d.ts b/types/next-auth.d.ts index e557e692..1bc5ca1c 100644 --- a/types/next-auth.d.ts +++ b/types/next-auth.d.ts @@ -1,12 +1,17 @@ -import NextAuth from 'next-auth'; - declare module 'next-auth' { - interface Session { - user: User; - } - interface User { id: string; pairwiseId: string; } + interface Account {} + interface Session {} +} + +import { JWT } from 'next-auth/jwt'; + +declare module 'next-auth/jwt' { + interface JWT { + sub: string; + pairwiseId: string; + } } From 98500082187ab761c9453042df489eade354e926 Mon Sep 17 00:00:00 2001 From: theexiile1305 Date: Sat, 4 May 2024 17:17:03 +0200 Subject: [PATCH 3/6] feat: better type decoration --- types/next-auth.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/types/next-auth.d.ts b/types/next-auth.d.ts index 1bc5ca1c..603fbf94 100644 --- a/types/next-auth.d.ts +++ b/types/next-auth.d.ts @@ -4,7 +4,9 @@ declare module 'next-auth' { pairwiseId: string; } interface Account {} - interface Session {} + interface Session { + user: User; + } } import { JWT } from 'next-auth/jwt'; From f217a84bba7fb00faea242936466dba6e03ee9be Mon Sep 17 00:00:00 2001 From: theexiile1305 Date: Sat, 4 May 2024 17:20:49 +0200 Subject: [PATCH 4/6] fix: env vars --- .github/workflows/quality-gate.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quality-gate.yml b/.github/workflows/quality-gate.yml index a0af82f8..f1eb6a80 100644 --- a/.github/workflows/quality-gate.yml +++ b/.github/workflows/quality-gate.yml @@ -82,10 +82,10 @@ jobs: - name: Run Playwright tests run: pnpm test:e2e env: - NEXTAUTH_URL: http://localhost:3000 + AUTH_URL: http://localhost:3000 + AUTH_SECRET: topsecret SHIBBOLETH_OIDC_ISSUER_URL: https://sso.hm.edu SHIBBOLETH_OIDC_SCOPE: openid - NEXTAUTH_SECRET: topsecret SHIBBOLETH_OIDC_CLIENT_ID: ${{ secrets.OIDC_CLIENT_ID }} SHIBBOLETH_OIDC_CLIENT_SECRET: ${{ secrets.OIDC_CLIENT_SECRET }} - uses: actions/upload-artifact@v4 From 98fd093829eaf288dc76d4268495b9e6975f87f2 Mon Sep 17 00:00:00 2001 From: theexiile1305 Date: Sat, 4 May 2024 17:29:03 +0200 Subject: [PATCH 5/6] chore: current state --- __tests__/auth.test.ts | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/__tests__/auth.test.ts b/__tests__/auth.test.ts index 680ae27a..05154bca 100644 --- a/__tests__/auth.test.ts +++ b/__tests__/auth.test.ts @@ -1,12 +1,18 @@ import { describe, it, expect, vi, afterAll, beforeAll } from 'vitest'; import { config } from '@/auth'; -describe('authOptions', () => { +describe('auth', () => { const mockUser = { id: '123', - email: '', - emailVerified: null, pairwiseId: '123', + email: 'email', + emailVerified: new Date(), + }; + + const mockAccount = { + provider: '', + providerAccountId: '', + type: 'oauth', }; const mockSession = { @@ -17,15 +23,17 @@ describe('authOptions', () => { emailVerified: null, }, sessionToken: '', - expires: new Date(), userId: '', }; const mockToken = { + id: mockUser.id, + sub: mockUser.id, pairwiseId: mockUser.pairwiseId, }; const mockProfile = { + sub: mockUser.id, pairwiseId: mockUser.pairwiseId, }; @@ -34,7 +42,7 @@ describe('authOptions', () => { return { appConfig: { nextAuth: { - debug: 'true', + secret: 'top-secret', }, shibboleth: { issuerUrl: 'http://localhost:8080', @@ -47,7 +55,7 @@ describe('authOptions', () => { }); }); - it('verify debug option is correctly set', async () => { + it('verify nextAuth debug is set', () => { expect(config.debug).toBeTruthy(); }); @@ -55,16 +63,15 @@ describe('authOptions', () => { const shibbolethProvider = config.providers[0]; expect(shibbolethProvider.id).toEqual('shibboleth'); expect(shibbolethProvider.name).toEqual('Shibboleth'); - expect(shibbolethProvider.type).toEqual('oidc'); + expect(shibbolethProvider.type).toEqual('oauth'); if (shibbolethProvider.type === 'oidc') { expect(shibbolethProvider.issuer).toEqual('http://localhost:8080'); + expect(shibbolethProvider.clientId).toEqual('client-id'); + expect(shibbolethProvider.clientSecret).toEqual('client-secret'); expect(shibbolethProvider.authorization).toEqual({ params: { scope: 'openid' }, }); - expect(shibbolethProvider.clientId).toEqual('client-id'); - expect(shibbolethProvider.clientSecret).toEqual('client-secret'); - const user = shibbolethProvider.profile(mockProfile); expect(user.id).toEqual(mockProfile.sub); expect(user.pairwiseId).toEqual(mockProfile.pairwiseId); @@ -75,6 +82,7 @@ describe('authOptions', () => { const session = await config.callbacks!!.session!!({ newSession: undefined, trigger: 'update', + // @ts-ignore session: mockSession, token: mockToken, user: mockUser, From ff9f0b8c0953ee6a2da6bdbb50d9c06aa8d60aef Mon Sep 17 00:00:00 2001 From: theexiile1305 Date: Thu, 3 Oct 2024 09:50:51 +0200 Subject: [PATCH 6/6] feat: update next-auth to version 5.0.0-beta.22 --- package.json | 2 +- pnpm-lock.yaml | 34 +++++++++++++++++----------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 46fe72be..fbc71294 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "eslint": "8.57.0", "eslint-config-next": "14.2.3", "next": "14.2.3", - "next-auth": "5.0.0-beta.17", + "next-auth": "5.0.0-beta.22", "react": "18.3.1", "react-dom": "18.3.1", "typescript": "5.4.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d969608a..e9e7b732 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,8 +48,8 @@ importers: specifier: 14.2.3 version: 14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next-auth: - specifier: 5.0.0-beta.17 - version: 5.0.0-beta.17(next@14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + specifier: 5.0.0-beta.22 + version: 5.0.0-beta.22(next@14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -101,8 +101,8 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@auth/core@0.30.0': - resolution: {integrity: sha512-8AE4m/nk+4EIiVCJwxZAsJeAQuzpEC8M8768mmKVn60CGDdupKQkVhxbRlm5Qh7eNRCoFFME+0DvtaX2aXrYaA==} + '@auth/core@0.35.3': + resolution: {integrity: sha512-g6qfiqU4OtyvIEZ8J7UoIwAxEnNnLJV0/f/DW41U+4G5nhBlaCrnKhawJIJpU0D3uavXLeDT3B0BkjtiimvMDA==} peerDependencies: '@simplewebauthn/browser': ^9.0.1 '@simplewebauthn/server': ^9.0.2 @@ -1915,14 +1915,14 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - next-auth@5.0.0-beta.17: - resolution: {integrity: sha512-XA/7JtAjOgDfAeotJPFUsFZGGItZwzZrxLt9Gc9fE7EchLk6zydZfuZ22Vvwixs3IilkN644D5IoD5tEOAFGCQ==} + next-auth@5.0.0-beta.22: + resolution: {integrity: sha512-QGBo9HGOjmnJBHGXvtFztl0tM5tL0porDlk74HVoCCzXd986ApOlIW3EmiCuho7YzEopgkFiwwmcXpoCrHAtYw==} peerDependencies: '@simplewebauthn/browser': ^9.0.1 '@simplewebauthn/server': ^9.0.2 - next: ^14 + next: ^14.0.0-0 || ^15.0.0-0 nodemailer: ^6.6.5 - react: ^18.2.0 + react: ^18.2.0 || ^19.0.0-0 peerDependenciesMeta: '@simplewebauthn/browser': optional: true @@ -2659,7 +2659,7 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@auth/core@0.30.0': + '@auth/core@0.35.3': dependencies: '@panva/hkdf': 1.1.1 '@types/cookie': 0.6.0 @@ -3915,7 +3915,7 @@ snapshots: '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.1(eslint@8.57.0) @@ -3938,12 +3938,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 4.3.4 enhanced-resolve: 5.16.0 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.3 @@ -3955,14 +3955,14 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.5) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -3976,7 +3976,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -4633,9 +4633,9 @@ snapshots: natural-compare@1.4.0: {} - next-auth@5.0.0-beta.17(next@14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): + next-auth@5.0.0-beta.22(next@14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1): dependencies: - '@auth/core': 0.30.0 + '@auth/core': 0.35.3 next: 14.2.3(@babel/core@7.24.4)(@playwright/test@1.43.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1