first commit
This commit is contained in:
71
src/routes/login.ts
Normal file
71
src/routes/login.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import type { APIContext } from "astro";
|
||||
import { options } from "../runtime.js";
|
||||
import {
|
||||
generateCodeVerifier,
|
||||
codeChallengeS256,
|
||||
generateState,
|
||||
generateNonce,
|
||||
} from "../lib/pkce.js";
|
||||
import { serializeCookie } from "../lib/cookies.js";
|
||||
|
||||
async function discover(issuer: string) {
|
||||
const res = await fetch(
|
||||
new URL("/.well-known/openid-configuration", issuer).toString(),
|
||||
);
|
||||
if (!res.ok) throw new Error(`OIDC discovery failed: ${res.status}`);
|
||||
return (await res.json()) as {
|
||||
authorization_endpoint: string;
|
||||
};
|
||||
}
|
||||
|
||||
function inferRedirectUri(reqUrl: URL): string {
|
||||
if ("absolute" in options.redirectUri) return options.redirectUri.absolute;
|
||||
const u = new URL(options.routes.callback, reqUrl);
|
||||
return u.toString();
|
||||
}
|
||||
|
||||
export async function GET(ctx: APIContext) {
|
||||
const { url } = ctx;
|
||||
const verifier = generateCodeVerifier();
|
||||
const challenge = await codeChallengeS256(verifier);
|
||||
const state = generateState();
|
||||
const nonce = generateNonce();
|
||||
|
||||
const returnTo = url.searchParams.get("return_to") || undefined;
|
||||
|
||||
const initPayload = JSON.stringify({
|
||||
state,
|
||||
nonce,
|
||||
verifier,
|
||||
return_to: returnTo,
|
||||
});
|
||||
const initCookieName = `${options.cookie.name}_init`;
|
||||
const cookie = serializeCookie(initCookieName, initPayload, {
|
||||
path: options.cookie.path,
|
||||
domain: options.cookie.domain,
|
||||
sameSite: "Lax",
|
||||
secure: options.cookie.secure,
|
||||
httpOnly: true,
|
||||
maxAge: 5 * 60, // 5 minutes
|
||||
});
|
||||
|
||||
const disco = await discover(options.issuer);
|
||||
const redirectUri = inferRedirectUri(url);
|
||||
const authorize = new URL(disco.authorization_endpoint);
|
||||
authorize.searchParams.set("client_id", options.clientId);
|
||||
authorize.searchParams.set("redirect_uri", redirectUri);
|
||||
authorize.searchParams.set("response_type", "code");
|
||||
authorize.searchParams.set("scope", options.scopes);
|
||||
authorize.searchParams.set("code_challenge", challenge);
|
||||
authorize.searchParams.set("code_challenge_method", "S256");
|
||||
authorize.searchParams.set("state", state);
|
||||
authorize.searchParams.set("nonce", nonce);
|
||||
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers: {
|
||||
Location: authorize.toString(),
|
||||
"Set-Cookie": cookie,
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user