mirror of
https://github.com/tale/headplane.git
synced 2026-08-05 19:57:42 +00:00
82 lines
2.1 KiB
TypeScript
82 lines
2.1 KiB
TypeScript
import * as oidc from "openid-client";
|
|
import { data, redirect } from "react-router";
|
|
|
|
import { HeadplaneConfig } from "~/server/config/config-schema";
|
|
import { createOidcStateCookie } from "~/utils/oidc-state";
|
|
|
|
import type { Route } from "./+types/oidc-start";
|
|
|
|
export async function loader({ request, context }: Route.LoaderArgs) {
|
|
try {
|
|
await context.auth.require(request);
|
|
return redirect("/");
|
|
} catch {}
|
|
|
|
const oidcConnector = await context.oidc?.connector.get();
|
|
if (!oidcConnector?.isValid) {
|
|
throw data("OIDC is not enabled or misconfigured", { status: 501 });
|
|
}
|
|
|
|
const cookie = createOidcStateCookie(context.config);
|
|
const redirect_uri = getRedirectUri(context.config, request);
|
|
|
|
const nonce = oidc.randomNonce();
|
|
const verifier = oidc.randomPKCECodeVerifier();
|
|
const state = oidc.randomState();
|
|
|
|
const url = oidc.buildAuthorizationUrl(oidcConnector.client, {
|
|
...oidcConnector.extraParams,
|
|
scope: oidcConnector.scope,
|
|
redirect_uri,
|
|
state,
|
|
nonce,
|
|
...(oidcConnector.usePKCE
|
|
? {
|
|
code_challenge_method: "S256",
|
|
code_challenge: await oidc.calculatePKCECodeChallenge(verifier),
|
|
}
|
|
: {}),
|
|
});
|
|
|
|
return redirect(url.href, {
|
|
status: 302,
|
|
headers: {
|
|
"Set-Cookie": await cookie.serialize({
|
|
state,
|
|
nonce,
|
|
verifier,
|
|
redirect_uri,
|
|
}),
|
|
},
|
|
});
|
|
}
|
|
|
|
function getRedirectUri(config: HeadplaneConfig, req: Request): string {
|
|
if (config.server.base_url != null) {
|
|
const url = new URL(`${__PREFIX__}/oidc/callback`, config.server.base_url);
|
|
return url.href;
|
|
}
|
|
|
|
if (config.oidc?.redirect_uri != null) {
|
|
const url = new URL(`${__PREFIX__}/oidc/callback`, config.oidc.redirect_uri);
|
|
return url.href;
|
|
}
|
|
|
|
const url = new URL(`${__PREFIX__}/oidc/callback`, req.url);
|
|
let host = req.headers.get("Host");
|
|
if (!host) {
|
|
host = req.headers.get("X-Forwarded-Host");
|
|
}
|
|
|
|
if (!host) {
|
|
throw data("Cannot determine redirect URI: no Host or X-Forwarded-Host header", {
|
|
status: 500,
|
|
});
|
|
}
|
|
|
|
const proto = req.headers.get("X-Forwarded-Proto");
|
|
url.protocol = proto ?? "http:";
|
|
url.host = host;
|
|
return url.href;
|
|
}
|