diff --git a/app/auth/callback/unilogin/route.ts b/app/auth/callback/unilogin/route.ts index 3ce37277..8a1b2073 100644 --- a/app/auth/callback/unilogin/route.ts +++ b/app/auth/callback/unilogin/route.ts @@ -2,7 +2,10 @@ import { NextRequest } from "next/server" import { IntrospectionResponse } from "openid-client" import goConfig from "@/lib/config/config" -import { getUniloginClient, uniloginClientConfig } from "@/lib/session/oauth/uniloginClient" +import { + getOpenIdClientUniloginClientConfig, + getUniloginClient, +} from "@/lib/session/oauth/uniloginClient" import { getSession, setTokensOnSession } from "@/lib/session/session" import { TTokenSet } from "@/lib/types/session" @@ -14,25 +17,22 @@ export interface TIntrospectionResponse extends IntrospectionResponse { } export async function GET(request: NextRequest) { - const configResponse = await fetch(`${process.env.NEXT_PUBLIC_APP_URL}/auth/config`) - if (!configResponse.ok) { - throw new Error("Failed to fetch config") + const session = await getSession() + const openIdClientConfig = await getOpenIdClientUniloginClientConfig() + if ( + !openIdClientConfig || + !openIdClientConfig.redirect_uri || + !openIdClientConfig.post_login_route + ) { + throw new Error("Unilogin client config is invalid.") } - const config = await configResponse.json() - const uniloginConfig = config?.dplConfiguration?.unilogin - const session = await getSession() - const client = await getUniloginClient({ - client_id: uniloginConfig.unilogin_api_client_id, - client_secret: uniloginConfig.unilogin_api_client_secret, - redirect_uri: `${process.env.NEXT_PUBLIC_APP_URL}/auth/callback/unilogin`, - wellKnownUrl: uniloginConfig.unilogin_api_wellknown_url, - }) + const client = await getUniloginClient() const params = client.callbackParams(request.nextUrl.toString()) // Fetch all user/token info. try { - const tokenSetResponse = await client.callback(uniloginClientConfig.redirect_uri, params, { + const tokenSetResponse = await client.callback(openIdClientConfig.redirect_uri, params, { code_verifier: session.code_verifier, }) const tokenSet = schemas.tokenSet.parse(tokenSetResponse) as TTokenSet @@ -61,7 +61,7 @@ export async function GET(request: NextRequest) { await session.save() - return Response.redirect(uniloginClientConfig.post_login_route) + return Response.redirect(openIdClientConfig.post_login_route) } catch (error) { console.error(error) // TODO: Error page or redirect to login page. diff --git a/app/auth/config/route.ts b/app/auth/config/route.ts deleted file mode 100644 index 7c5f54c7..00000000 --- a/app/auth/config/route.ts +++ /dev/null @@ -1,36 +0,0 @@ -export const revalidate = 1 - -export const query = ` - query getUniLoginConfiguration { - dplConfiguration { - unilogin { - unilogin_api_url - unilogin_api_wellknown_url - unilogin_api_client_id - unilogin_api_client_secret - } - } - }` - -export async function GET() { - const res = await fetch(`${process.env.NEXT_PUBLIC_GRAPHQL_SCHEMA_ENDPOINT_DPL_CMS}`, { - method: "POST", - ...{ - headers: { - "Content-Type": "application/json", - Authorization: "Basic " + process.env.GRAPHQL_SCHEMA_ENDPOINT_DPL_CMS_AUTH_HEADER, - }, - }, - body: JSON.stringify({ query }), - }) - - const json = await res.json() - - if (json.errors) { - const { message } = json.errors[0] - - throw new Error(message) - } - - return Response.json(json.data) -} diff --git a/app/auth/login/unilogin/route.ts b/app/auth/login/unilogin/route.ts index f5f35dec..7cadab9d 100644 --- a/app/auth/login/unilogin/route.ts +++ b/app/auth/login/unilogin/route.ts @@ -1,38 +1,39 @@ import { generators } from "openid-client" -import { getUniloginClient } from "@/lib/session/oauth/uniloginClient" +import { + getOpenIdClientUniloginClientConfig, + getUniloginClient, +} from "@/lib/session/oauth/uniloginClient" import { getSession } from "@/lib/session/session" -export const revalidate = 1 - export async function GET() { - const configResponse = await fetch(`${process.env.NEXT_PUBLIC_APP_URL}/auth/config`) - if (!configResponse.ok) { - throw new Error("Failed to fetch config") - } - const config = await configResponse.json() - const uniloginConfig = config?.dplConfiguration?.unilogin - const session = await getSession() - session.code_verifier = generators.codeVerifier() - const client = await getUniloginClient({ - client_id: uniloginConfig.unilogin_api_client_id, - client_secret: uniloginConfig.unilogin_api_client_secret, - redirect_uri: `${process.env.NEXT_PUBLIC_APP_URL}/auth/callback/unilogin`, - wellKnownUrl: uniloginConfig.unilogin_api_wellknown_url, - }) + session.code_verifier = generators.codeVerifier() const code_challenge = generators.codeChallenge(session.code_verifier) + + const openIdClientConfig = await getOpenIdClientUniloginClientConfig() + + if ( + !openIdClientConfig || + !openIdClientConfig.scope || + !openIdClientConfig.redirect_uri || + !openIdClientConfig.audience + ) { + throw new Error("Unilogin client config is invalid.") + } + + const client = await getUniloginClient() + const url = client.authorizationUrl({ - scope: "openid", - audience: process.env.UNILOGIN_API_URL, - redirect_uri: `${process.env.NEXT_PUBLIC_APP_URL}/auth/callback/unilogin`, + scope: openIdClientConfig.scope, + audience: openIdClientConfig.audience, + redirect_uri: openIdClientConfig.redirect_uri, code_challenge, code_challenge_method: "S256", }) await session.save() - return Response.redirect(url) } diff --git a/app/auth/logout/route.ts b/app/auth/logout/route.ts index a1f6ca19..e29852fe 100644 --- a/app/auth/logout/route.ts +++ b/app/auth/logout/route.ts @@ -2,17 +2,13 @@ import { cookies } from "next/headers" import { generators } from "openid-client" import goConfig from "@/lib/config/config" -import { getUniloginClient, uniloginClientConfig } from "@/lib/session/oauth/uniloginClient" +import { + getOpenIdClientUniloginClientConfig, + getUniloginClient, +} from "@/lib/session/oauth/uniloginClient" import { getSession } from "@/lib/session/session" export async function GET() { - const configResponse = await fetch(`${process.env.NEXT_PUBLIC_APP_URL}/auth/config`) - if (!configResponse.ok) { - throw new Error("Failed to fetch config") - } - const config = await configResponse.json() - const uniloginConfig = config?.dplConfiguration?.unilogin - const session = await getSession() // TODO: Distinguish between session types here. const id_token = cookies().get("go-session:id_token")?.value @@ -20,14 +16,17 @@ export async function GET() { if (!id_token) { return Response.redirect(goConfig("app.url")) } - const client = await getUniloginClient({ - client_id: uniloginConfig.unilogin_api_client_id, - client_secret: uniloginConfig.unilogin_api_client_secret, - redirect_uri: `${process.env.NEXT_PUBLIC_APP_URL}/auth/callback/unilogin`, - wellKnownUrl: uniloginConfig.unilogin_api_wellknown_url, - }) + + const openIdClientConfig = await getOpenIdClientUniloginClientConfig() + + if (!openIdClientConfig || !openIdClientConfig.post_logout_redirect_uri) { + throw new Error("Unilogin client config is invalid.") + } + + const client = await getUniloginClient() + const endSession = client.endSessionUrl({ - post_logout_redirect_uri: uniloginClientConfig.post_logout_redirect_uri, + post_logout_redirect_uri: openIdClientConfig.post_logout_redirect_uri, id_token_hint: id_token, state: generators.state(), }) diff --git a/app/auth/token/refresh/route.ts b/app/auth/token/refresh/route.ts index 054a9b48..b5b44053 100644 --- a/app/auth/token/refresh/route.ts +++ b/app/auth/token/refresh/route.ts @@ -2,7 +2,10 @@ import { NextRequest, NextResponse } from "next/server" import { z } from "zod" import goConfig from "@/lib/config/config" -import { getUniloginClient } from "@/lib/session/oauth/uniloginClient" +import { + getOpenIdClientUniloginClientConfig, + getUniloginClient, +} from "@/lib/session/oauth/uniloginClient" import { getSession, setTokensOnSession } from "@/lib/session/session" import { TTokenSet } from "@/lib/types/session" @@ -13,14 +16,7 @@ const sessionTokenSchema = z.object({ }) export async function GET(request: NextRequest, response: NextResponse) { - const configResponse = await fetch(`${process.env.NEXT_PUBLIC_APP_URL}/auth/config`) - if (!configResponse.ok) { - throw new Error("Failed to fetch config") - } - const config = await configResponse.json() - const uniloginConfig = config?.dplConfiguration?.unilogin - - const appUrl = goConfig("app.url") + const appUrl = goConfig("app.url") const session = await getSession() const frontpage = `${appUrl}/` @@ -37,12 +33,8 @@ export async function GET(request: NextRequest, response: NextResponse) { try { // TODO: Consider if we want to handle different types of sessions than unilogin. const tokens = sessionTokenSchema.parse(session) - const client = await getUniloginClient({ - client_id: uniloginConfig.unilogin_api_client_id, - client_secret: uniloginConfig.unilogin_api_client_secret, - redirect_uri: `${process.env.NEXT_PUBLIC_APP_URL}/auth/callback/unilogin`, - wellKnownUrl: uniloginConfig.unilogin_api_wellknown_url, - }) + const client = await getUniloginClient() + const newTokens = await (client.refresh(tokens.refresh_token) as Promise) setTokensOnSession(session, newTokens) await session.save() diff --git a/app/layout.tsx b/app/layout.tsx index 298bf43f..d08855c0 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,4 +1,3 @@ -import { QueryClient } from "@tanstack/react-query" import type { Metadata } from "next" import localFont from "next/font/local" @@ -6,12 +5,6 @@ import Footer from "@/components/global/footer/Footer" import GridHelper from "@/components/global/gridHelper/GridHelper" import Header from "@/components/global/header/Header" import Theme from "@/components/global/theme/Theme" -import getQueryClient from "@/lib/getQueryClient" -import { - GetUniLoginConfigurationQuery, - useGetUniLoginConfigurationQuery, -} from "@/lib/graphql/generated/dpl-cms/graphql" -import ConfigProvider from "@/lib/providers/ConfigProvider" import ReactQueryProvider from "@/lib/providers/ReactQueryProvider" import "@/styles/globals.css" @@ -42,38 +35,23 @@ const GTFlexa = localFont({ display: "swap", }) -const getConfiguration = async (queryClient: QueryClient) => { - const data = await queryClient.fetchQuery({ - queryKey: useGetUniLoginConfigurationQuery.getKey(), - queryFn: useGetUniLoginConfigurationQuery.fetcher(), - }) - - return data -} - -export default async function RootLayout({ +export default function RootLayout({ children, }: Readonly<{ children: React.ReactNode }>) { - // This is a workaround to ensure that the uniloginConfiguration is loaded before the app is rendered - const queryClient = getQueryClient() - const configuration = await getConfiguration(queryClient) - return ( - - -
-
- {children} -
-