diff --git a/components/Auth/OpenID.vue b/components/Auth/OpenID.vue index 926e110..5783816 100644 --- a/components/Auth/OpenID.vue +++ b/components/Auth/OpenID.vue @@ -1,10 +1,14 @@ + + diff --git a/server/internal/oidc/index.ts b/server/internal/oidc/index.ts index 24c4e33..ec5f43e 100644 --- a/server/internal/oidc/index.ts +++ b/server/internal/oidc/index.ts @@ -1,5 +1,6 @@ import { randomUUID } from "crypto"; import prisma from "../db/database"; +import type { User } from "~/prisma/client"; import { AuthMec } from "~/prisma/client"; import objectHandler from "../objects"; import type { Readable } from "stream"; @@ -12,10 +13,15 @@ interface OIDCWellKnown { scopes_supported: string[]; } +interface OIDCAuthSessionOptions { + redirect: string | undefined; +} + interface OIDCAuthSession { redirectUrl: string; callbackUrl: string; state: string; + options: OIDCAuthSessionOptions; } interface OIDCUserInfo { @@ -132,7 +138,7 @@ export class OIDCManager { }; } - generateAuthSession(): OIDCAuthSession { + generateAuthSession(options?: OIDCAuthSessionOptions): OIDCAuthSession { const stateKey = randomUUID(); const normalisedUrl = new URL( @@ -148,12 +154,16 @@ export class OIDCManager { redirectUrl: finalUrl, callbackUrl: redirectUrl, state: stateKey, + options: options ?? { redirect: undefined }, }; this.signinStateTable[stateKey] = session; return session; } - async authorize(code: string, state: string) { + async authorize( + code: string, + state: string, + ): Promise<{ user: User; options: OIDCAuthSessionOptions } | string> { const session = this.signinStateTable[state]; if (!session) return "Invalid state parameter"; @@ -191,7 +201,9 @@ export class OIDCManager { const user = await this.fetchOrCreateUser(userinfo); - return user; + if (typeof user === "string") return user; + + return { user, options: session.options }; } catch (e) { console.error(e); return `Request to identity provider failed: ${e}`; diff --git a/server/routes/auth/callback/oidc.get.ts b/server/routes/auth/callback/oidc.get.ts index e2a6854..0bedf34 100644 --- a/server/routes/auth/callback/oidc.get.ts +++ b/server/routes/auth/callback/oidc.get.ts @@ -21,15 +21,19 @@ export default defineEventHandler(async (h3) => { statusMessage: "No state in query params.", }); - const user = await manager.authorize(code, state); + const result = await manager.authorize(code, state); - if (typeof user === "string") + if (typeof result === "string") throw createError({ statusCode: 403, - statusMessage: `Failed to sign in: "${user}". Please try again.`, + statusMessage: `Failed to sign in: "${result}". Please try again.`, }); - await sessionHandler.signin(h3, user.id, true); + await sessionHandler.signin(h3, result.user.id, true); + + if (result.options.redirect) { + return sendRedirect(h3, result.options.redirect); + } return sendRedirect(h3, "/"); }); diff --git a/server/routes/auth/oidc.get.ts b/server/routes/auth/oidc.get.ts index be3cf94..a2b89e9 100644 --- a/server/routes/auth/oidc.get.ts +++ b/server/routes/auth/oidc.get.ts @@ -1,10 +1,16 @@ import { enabledAuthManagers } from "~/server/plugins/04.auth-init"; export default defineEventHandler((h3) => { - if (!enabledAuthManagers.OpenID) return sendRedirect(h3, "/auth/signin"); + const redirect = getQuery(h3).redirect?.toString(); + + if (!enabledAuthManagers.OpenID) + return sendRedirect( + h3, + `/auth/signin${redirect ? `?redirect=${encodeURIComponent(redirect)}` : ""}`, + ); const manager = enabledAuthManagers.OpenID; - const { redirectUrl } = manager.generateAuthSession(); + const { redirectUrl } = manager.generateAuthSession({ redirect }); return sendRedirect(h3, redirectUrl); });