Skip to content

Commit

Permalink
Moving configuration fetching inside getUniloginClient
Browse files Browse the repository at this point in the history
No need to repeat configuration fetching outside of it.
  • Loading branch information
spaceo committed Nov 20, 2024
1 parent 8b2d37e commit 355f715
Show file tree
Hide file tree
Showing 15 changed files with 250 additions and 332 deletions.
30 changes: 15 additions & 15 deletions app/auth/callback/unilogin/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down
36 changes: 0 additions & 36 deletions app/auth/config/route.ts

This file was deleted.

43 changes: 22 additions & 21 deletions app/auth/login/unilogin/route.ts
Original file line number Diff line number Diff line change
@@ -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)
}
29 changes: 14 additions & 15 deletions app/auth/logout/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,31 @@ 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
// TODO: Is this where we want to redirect to if id token cannot be resolved?
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(),
})
Expand Down
22 changes: 7 additions & 15 deletions app/auth/token/refresh/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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<string>("app.url")
const session = await getSession()
const frontpage = `${appUrl}/`

Expand All @@ -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<TTokenSet>)
setTokensOnSession(session, newTokens)
await session.save()
Expand Down
38 changes: 8 additions & 30 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { QueryClient } from "@tanstack/react-query"
import type { Metadata } from "next"
import localFont from "next/font/local"

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"

Expand Down Expand Up @@ -42,38 +35,23 @@ const GTFlexa = localFont({
display: "swap",
})

const getConfiguration = async (queryClient: QueryClient) => {
const data = await queryClient.fetchQuery<GetUniLoginConfigurationQuery>({
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 (
<html lang="en">
<body className={`${GTFlexa.variable} antialiased`}>
<GridHelper hideInProduction />
<Theme>
<ConfigProvider uniloginConfiguration={configuration.dplConfiguration?.unilogin || {}}>
<ReactQueryProvider>
<Header />
<div className="flex h-full min-h-screen-minus-navigation-height w-full flex-col">
{children}
</div>
<Footer />
</ReactQueryProvider>
</ConfigProvider>
<ReactQueryProvider>
<Header />
<div className="flex h-full min-h-screen-minus-navigation-height w-full flex-col">
{children}
</div>
<Footer />
</ReactQueryProvider>
</Theme>
</body>
</html>
Expand Down
11 changes: 4 additions & 7 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
"use client"

import Image from "next/image"

import { useConfigStore } from "@/store/config.store"

export default function Home() {
const config = useConfigStore()
import goConfig from "@/lib/config/config"

const wellknownUrl = goConfig<Promise<string | undefined>>("service.unilogin.wellknown.url")
export default async function Home() {
return (
<div
className="grid min-h-screen grid-rows-[20px_1fr_20px] items-center justify-items-center gap-16 p-8 pb-20
font-[family-name:var(--font-geist-sans)] sm:p-20">
<main className="row-start-2 flex flex-col items-center gap-8 sm:items-start">
<pre>{<pre>{JSON.stringify(config, null, 2)}</pre>}</pre>
<pre>Wellknown url: {wellknownUrl}</pre>
<Image
className="dark:invert"
src="https://nextjs.org/icons/next.svg"
Expand Down
2 changes: 1 addition & 1 deletion codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const config: CodegenConfig = {
schema: {
[`${process.env.NEXT_PUBLIC_GRAPHQL_SCHEMA_ENDPOINT_DPL_CMS}`]: {
headers: {
Authorization: `Basic ${process.env.GRAPHQL_SCHEMA_ENDPOINT_DPL_CMS_AUTH_HEADER}`,
Authorization: `Basic ${process.env.GRAPHQL_SCHEMA_ENDPOINT_BASIC_TOKEN_DPL_CMS}`,
},
},
},
Expand Down
2 changes: 0 additions & 2 deletions lib/config/config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import MissingConfigurationError from "./errors/MissingConfigurationError"
import app from "./resolvers/app"
import search from "./resolvers/search"
import serviceDplCms from "./resolvers/service.dpl-cms"
import serviceFbi from "./resolvers/service.fbi"
import serviceUnilogin from "./resolvers/service.unilogin"
import token from "./resolvers/token"

const resolvers = {
...app,
...serviceDplCms,
...serviceFbi,
...serviceUnilogin,
...search,
Expand Down
14 changes: 0 additions & 14 deletions lib/config/resolvers/service.dpl-cms.ts

This file was deleted.

Loading

0 comments on commit 355f715

Please sign in to comment.