From bfa1c7879be760a8ef9c08edf45c0dd58b47fadb Mon Sep 17 00:00:00 2001 From: Mark Hoekveen Date: Wed, 25 Jun 2025 16:38:22 +0200 Subject: [PATCH] Authentication? Voor een gegeven definitie van... --- frontend/package-lock.json | 38 ++++++++++++++++++++++++- frontend/package.json | 4 ++- frontend/src/app/auth/callback/page.tsx | 16 +++++++++++ frontend/src/app/layout.tsx | 4 ++- frontend/src/app/page.tsx | 37 ++++++++++++++++++++++-- frontend/src/config/auth.ts | 23 +++++++++++++++ frontend/tsconfig.json | 26 +++++++---------- 7 files changed, 128 insertions(+), 20 deletions(-) create mode 100644 frontend/src/app/auth/callback/page.tsx create mode 100644 frontend/src/config/auth.ts diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 95ebb1e..1167eee 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -6,8 +6,10 @@ "": { "dependencies": { "next": "^15.3.3", + "oidc-client-ts": "^3.3.0", "react": "^19.1.0", - "react-dom": "^19.1.0" + "react-dom": "^19.1.0", + "react-oidc-context": "^3.3.0" }, "devDependencies": { "@tailwindcss/postcss": "^4.1.10", @@ -1109,6 +1111,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/lightningcss": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", @@ -1497,6 +1508,18 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/oidc-client-ts": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-3.3.0.tgz", + "integrity": "sha512-t13S540ZwFOEZKLYHJwSfITugupW4uYLwuQSSXyKH/wHwZ+7FvgHE7gnNJh1YQIZ1Yd1hKSRjqeXGSUtS0r9JA==", + "license": "Apache-2.0", + "dependencies": { + "jwt-decode": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -1553,6 +1576,19 @@ "react": "^19.1.0" } }, + "node_modules/react-oidc-context": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/react-oidc-context/-/react-oidc-context-3.3.0.tgz", + "integrity": "sha512-302T/ma4AOVAxrHdYctDSKXjCq9KNHT564XEO2yOPxRfxEP58xa4nz+GQinNl8x7CnEXECSM5JEjQJk3Cr5BvA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "oidc-client-ts": "^3.1.0", + "react": ">=16.14.0" + } + }, "node_modules/scheduler": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index e5af076..ed41913 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,8 +1,10 @@ { "dependencies": { "next": "^15.3.3", + "oidc-client-ts": "^3.3.0", "react": "^19.1.0", - "react-dom": "^19.1.0" + "react-dom": "^19.1.0", + "react-oidc-context": "^3.3.0" }, "scripts": { "dev": "next dev", diff --git a/frontend/src/app/auth/callback/page.tsx b/frontend/src/app/auth/callback/page.tsx new file mode 100644 index 0000000..a31bb8c --- /dev/null +++ b/frontend/src/app/auth/callback/page.tsx @@ -0,0 +1,16 @@ +"use client"; + +import { useEffect } from "react"; +import { userManager } from "muzak/config/auth"; +import { useRouter } from "next/navigation"; + +export default function SignInCallback() { + const router = useRouter(); + + useEffect(() => { + userManager.signinCallback(); + router.push("/"); + }, []); + + return <>; +} diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index e41f38f..10f8e02 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -1,6 +1,8 @@ "use client"; import "./style.css"; import { useState } from "react"; +import { AuthProvider } from "react-oidc-context"; +import { oidcConfig, userManager } from "muzak/config/auth"; export default function RootLayout({ children, @@ -16,7 +18,7 @@ export default function RootLayout({ return ( - {children} + {children} + )} + {!auth.isAuthenticated && ( + + )} Meowl image - + ); } diff --git a/frontend/src/config/auth.ts b/frontend/src/config/auth.ts new file mode 100644 index 0000000..96246df --- /dev/null +++ b/frontend/src/config/auth.ts @@ -0,0 +1,23 @@ +import { UserManager } from "oidc-client-ts"; +import { AuthProviderProps } from "react-oidc-context"; + +const ORIGIN_URI = globalThis?.window?.location.origin; +const REDIRECT_URI = `${ORIGIN_URI}/auth/callback`; + +const userConfig: AuthProviderProps = { + authority: process.env.NEXT_PUBLIC_AUTHORITY!, + client_id: process.env.NEXT_PUBLIC_CLIENT_ID!, + client_secret: process.env.NEXT_PUBLIC_CLIENT_SECRET!, + redirect_uri: REDIRECT_URI, + response_type: "code", + includeIdTokenInSilentRenew: true, + automaticSilentRenew: false, //TODO: Dit moet dus denk ik wel gewoon aan? + scope: "openid profile email offline_access", //TODO: Iets met scopes. + accessTokenExpiringNotificationTimeInSeconds: 5 * 60, + loadUserInfo: true, + post_logout_redirect_uri: ORIGIN_URI, + response_mode: "query", +}; + +export const userManager = new UserManager(userConfig); +export const oidcConfig = { ...userConfig, userManager }; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index f619795..b7a8edc 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,12 +1,15 @@ { "compilerOptions": { "target": "ES2017", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, + "lib": ["dom", "dom.iterable", "esnext"], + + // Make local stuff available for non-relative import + "baseUrl": "./", + "paths": { + "muzak/config/*": ["./src/config/*"] + }, + + "allowJs": false, "skipLibCheck": true, "strict": false, "noEmit": true, @@ -23,13 +26,6 @@ } ] }, - "include": [ - "next-env.d.ts", - ".next/types/**/*.ts", - "**/*.ts", - "**/*.tsx" - ], - "exclude": [ - "node_modules" - ] + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] }