This repository has been archived on 2025-11-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
trafficcue-client/src/lib/services/oidc.ts
Cfp 5e186397dd feat!: replace auth with OIDC
Remove better-auth and replace it with OIDC
2025-06-22 11:41:28 +02:00

80 lines
2.3 KiB
TypeScript

// OIDC Server needs to have redirect url for /login/callback
import { getOIDCConfig } from "./lnv";
const oidcConfig = await getOIDCConfig();
if (!oidcConfig) {
throw new Error("Server does not support OIDC authentication");
}
const { AUTH_URL, CLIENT_ID, TOKEN_URL } = oidcConfig;
export { CLIENT_ID, TOKEN_URL };
export async function getAuthURL() {
const pkce = await generatePKCEChallenge();
const state = generateRandomString(16);
return {
url:
`${AUTH_URL}?client_id=${CLIENT_ID}&response_type=code&redirect_uri=${window.location.origin}/login/callback&scope=openid%20profile&code_challenge=${pkce.codeChallenge}&code_challenge_method=S256&state=${state}`,
codeVerifier: pkce.codeVerifier,
state,
};
}
// Function to generate PKCE code challenge
// With the S256 method
async function generatePKCEChallenge() {
const codeVerifier = generateRandomString(128);
const codeChallengeBuf = await sha256(codeVerifier);
const codeChallenge = base64URLEncode(new Uint8Array(codeChallengeBuf));
return { codeVerifier, codeChallenge };
}
// Generates a cryptographically secure random string
function generateRandomString(length: number) {
const array = new Uint32Array(length / 2);
window.crypto.getRandomValues(array);
return Array.from(array, (dec) => ("0" + dec.toString(16)).substr(-2)).join("");
}
// Encodes a string to base64url (no padding)
function base64URLEncode(buffer: Uint8Array) {
return btoa(String.fromCharCode(...buffer))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
}
async function sha256(input: string | undefined): Promise<ArrayBuffer> {
const encoder = new TextEncoder();
const data = encoder.encode(input);
return await window.crypto.subtle.digest("SHA-256", data);
}
export async function getOIDCUser(code: string, codeVerifier: string) {
const params = new URLSearchParams();
params.append("grant_type", "authorization_code");
params.append("code", code);
params.append("client_id", CLIENT_ID);
params.append("code_verifier", codeVerifier);
params.append("redirect_uri", window.location.origin + "/login/callback");
const res = await fetch(TOKEN_URL, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: params
}).then(res => res.json());
return res;
// return JSON.parse(atob(id_token.split(".")[1]));
}