Create Foundation OAuth client helper
cgen-4cb4790703c748279144104b92975975
This commit is contained in:
parent
40c025396d
commit
7859213af2
1 changed files with 99 additions and 0 deletions
99
client/lib/foundation-oauth.ts
Normal file
99
client/lib/foundation-oauth.ts
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Foundation OAuth Client
|
||||
*
|
||||
* This module handles the OAuth flow with aethex.foundation as the identity provider.
|
||||
* aethex.dev acts as an OAuth client, redirecting users to Foundation for authentication.
|
||||
*/
|
||||
|
||||
const FOUNDATION_URL = import.meta.env.VITE_FOUNDATION_URL || "https://aethex.foundation";
|
||||
const API_BASE = import.meta.env.VITE_API_BASE || "https://aethex.dev";
|
||||
|
||||
/**
|
||||
* Generate authorization URL for redirecting to Foundation login
|
||||
*/
|
||||
export function getFoundationAuthorizationUrl(options?: {
|
||||
redirectTo?: string;
|
||||
state?: string;
|
||||
}): string {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
// client_id identifies aethex.dev as the client
|
||||
params.set("client_id", "aethex-corp");
|
||||
|
||||
// Redirect back to aethex.dev after authentication
|
||||
params.set("redirect_uri", `${API_BASE}/api/auth/foundation-callback`);
|
||||
|
||||
// OAuth standard - maintain context across redirect
|
||||
params.set("response_type", "code");
|
||||
params.set("scope", "openid profile email");
|
||||
|
||||
// Custom state for additional context
|
||||
if (options?.state) {
|
||||
params.set("state", options.state);
|
||||
}
|
||||
|
||||
return `${FOUNDATION_URL}/api/oauth/authorize?${params.toString()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the OAuth flow by redirecting to Foundation
|
||||
*/
|
||||
export function initiateFoundationLogin(redirectTo?: string): void {
|
||||
// Store intended destination for after auth
|
||||
if (redirectTo) {
|
||||
sessionStorage.setItem("auth_redirect_to", redirectTo);
|
||||
}
|
||||
|
||||
const state = JSON.stringify({
|
||||
redirectTo: redirectTo || "/dashboard",
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
|
||||
const authUrl = getFoundationAuthorizationUrl({
|
||||
redirectTo,
|
||||
state: encodeURIComponent(state),
|
||||
});
|
||||
|
||||
window.location.href = authUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exchange authorization code for token
|
||||
* This is called from the Foundation callback endpoint on the backend
|
||||
*/
|
||||
export async function exchangeCodeForToken(code: string): Promise<{
|
||||
accessToken: string;
|
||||
user: any;
|
||||
}> {
|
||||
const response = await fetch(`${API_BASE}/api/auth/exchange-token`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ code }),
|
||||
credentials: "include", // Include cookies for session
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({}));
|
||||
throw new Error(error.message || "Failed to exchange code for token");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored redirect destination after auth
|
||||
*/
|
||||
export function getStoredRedirectTo(): string | null {
|
||||
if (typeof window === "undefined") return null;
|
||||
return sessionStorage.getItem("auth_redirect_to");
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the stored redirect destination
|
||||
*/
|
||||
export function clearStoredRedirectTo(): void {
|
||||
if (typeof window === "undefined") return;
|
||||
sessionStorage.removeItem("auth_redirect_to");
|
||||
}
|
||||
Loading…
Reference in a new issue