From 6b4eb46c39e9ffd61fb21c5e15d7146db88ddbd1 Mon Sep 17 00:00:00 2001 From: Oscar Eriksson Date: Thu, 24 Oct 2024 19:49:44 +0200 Subject: [PATCH] Make oauth state cookie work --- frontend/src/app/page.tsx | 13 +++--- frontend/src/app/unauthorized/page.tsx | 5 ++- frontend/src/lib/goldapps/auth.ts | 60 +++++++++++++++----------- frontend/src/middleware.ts | 32 +++++++++++--- 4 files changed, 69 insertions(+), 41 deletions(-) diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index d055398..751c59d 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -4,17 +4,14 @@ import { redirect } from "next/navigation"; import { getSuggestions } from "../lib/goldapps/get-suggestions"; import { createGoldappsServerClient } from "../lib/goldapps/client-server"; -async function fetchSuggestions() { - const goldappsClient = createGoldappsServerClient(); - const redirectUri = await checkLogin(); - if (redirectUri) { - return redirect(redirectUri); - } - return getSuggestions(goldappsClient); -} export default async function IndexPage() { + const fetchSuggestions = async () => { + const goldappsClient = createGoldappsServerClient(); + return getSuggestions(goldappsClient); + } + const suggestions = await fetchSuggestions(); return ; } diff --git a/frontend/src/app/unauthorized/page.tsx b/frontend/src/app/unauthorized/page.tsx index bef9dd7..519cee1 100644 --- a/frontend/src/app/unauthorized/page.tsx +++ b/frontend/src/app/unauthorized/page.tsx @@ -1,11 +1,12 @@ -export default function UnauthorizedPage() { +export default async function UnauthorizedPage() { + return (

Unauthorized!

You are not authorized to use this website

For more information, please contact IT responsible at the IT student - division or digIT + division.

); diff --git a/frontend/src/lib/goldapps/auth.ts b/frontend/src/lib/goldapps/auth.ts index 5dbc191..845a528 100644 --- a/frontend/src/lib/goldapps/auth.ts +++ b/frontend/src/lib/goldapps/auth.ts @@ -1,42 +1,54 @@ 'use server'; -import { AxiosResponse } from "axios"; +import { AxiosHeaders, AxiosResponse, RawAxiosResponseHeaders } from "axios"; import { cookies } from "next/headers"; import { createGoldappsServerClient } from "./client-server"; +import { ResponseCookie } from "next/dist/compiled/@edge-runtime/cookies"; + +function extractOauthStateCookie(headers: RawAxiosResponseHeaders | (RawAxiosResponseHeaders & AxiosHeaders)): ResponseCookie | null { + if (headers === null || headers === undefined) { + return null; + } + const setCookieHeader = headers["set-cookie"] || null; + const serverCookies = (Array.isArray(setCookieHeader) ? setCookieHeader : [setCookieHeader]).map((cookie) => { + if (typeof cookie === "string") { + const [nameValue, ...rest] = cookie.split(";"); + const [name, value] = nameValue.split("="); + return { name, value, attributes: rest.join(";") }; + } + return null; + }).filter(cookie => cookie !== null) || []; + + const oauthStateCookie = serverCookies.find((cookie: any) => cookie.name === "oauth_state"); + + if (oauthStateCookie) { + return { + name: "oauth_state", + value: oauthStateCookie.value, + maxAge: 3600, // 1 hour + httpOnly: true, + secure: true, + sameSite: "none", + }; + } + return null +} // Returns login uri if not logged in -export async function checkLogin() { +export async function checkLogin() : Promise<{data: string, cookie: (ResponseCookie | null)} | null> { try { + const client = createGoldappsServerClient(); const { status: checkLoginStatus, data, headers } = await client.get( - "/api/checkLogin", + "/api/checkLogin" ); if (checkLoginStatus !== 200) { - const serverCookies = headers["set-cookie"]?.map((cookie) => { - const [nameValue, ...rest] = cookie.split(';'); - const [name, value] = nameValue.split('='); - return { name, value, attributes: rest.join(';') }; - }) || []; - - const oauthStateCookie = serverCookies.find((cookie) => cookie.name === "oauth_state"); - - if (oauthStateCookie) { - cookies().set({ - name: "oauth_state", - value: oauthStateCookie.value, - maxAge: 3600, // 1 hour - httpOnly: true, - secure: true, - sameSite: "none" - }); - } - - return data; + return {data, cookie: extractOauthStateCookie(headers)}; } return null; } catch (e) { const response = (e as any).response as AxiosResponse; - return response.data; + return {data: response.data, cookie: extractOauthStateCookie(response.headers)}; } } diff --git a/frontend/src/middleware.ts b/frontend/src/middleware.ts index da1237a..bf3a2f5 100644 --- a/frontend/src/middleware.ts +++ b/frontend/src/middleware.ts @@ -1,13 +1,31 @@ import { NextResponse } from "next/server"; import type { NextRequest } from "next/server"; +import { createGoldappsServerClient } from "./lib/goldapps/client-server"; +import { checkLogin } from "./lib/goldapps/auth"; + +export async function middleware(request: NextRequest) { -export function middleware(request: NextRequest) { const GOLDAPPS_URL = process.env.GOLDAPPS_URL || "http://localhost:8080"; - return NextResponse.rewrite( - GOLDAPPS_URL + request.nextUrl.pathname + request.nextUrl.search, - ); + if (request.nextUrl.pathname === "/") { + const loginStatus = await checkLogin(); + if (loginStatus?.data){ + const redirectResponse = NextResponse.redirect(loginStatus.data); + + if (loginStatus.cookie) + redirectResponse.cookies.set(loginStatus.cookie); + + return redirectResponse; + } + } + + if (request.nextUrl.pathname.startsWith("/api/")) { + return NextResponse.rewrite( + GOLDAPPS_URL + request.nextUrl.pathname + request.nextUrl.search, + ); + } + return NextResponse.next(); } -export const config = { - matcher: "/api/:path*", -}; +//export const config = { +// matcher: "/api/:path*", +//};