6f18dd24a5
- Add OIDC authentication with PKCE flow - Create dashboard shell with sidebar and header - Implement project management UI (list, create, detail) - Add tool spawn page with tool/project selection - Create tool instance detail page with status and controls - Set up React Router with route guards - Add Zustand auth store and API client with types
48 lines
1.4 KiB
TypeScript
48 lines
1.4 KiB
TypeScript
// PKCE utilities for OIDC flow
|
|
function generateRandomString(length: number): string {
|
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
|
let text = ''
|
|
for (let i = 0; i < length; i++) {
|
|
text += possible.charAt(Math.floor(Math.random() * possible.length))
|
|
}
|
|
return text
|
|
}
|
|
|
|
async function generateCodeChallenge(verifier: string): Promise<string> {
|
|
const encoder = new TextEncoder()
|
|
const data = encoder.encode(verifier)
|
|
const digest = await crypto.subtle.digest('SHA-256', data)
|
|
const base64 = btoa(String.fromCharCode(...new Uint8Array(digest)))
|
|
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
|
|
}
|
|
|
|
export async function createPKCE(): Promise<{ verifier: string; challenge: string }> {
|
|
const verifier = generateRandomString(128)
|
|
const challenge = await generateCodeChallenge(verifier)
|
|
return { verifier, challenge }
|
|
}
|
|
|
|
export function storePKCE(verifier: string): void {
|
|
sessionStorage.setItem('pkce_verifier', verifier)
|
|
}
|
|
|
|
export function getPKCE(): string | null {
|
|
return sessionStorage.getItem('pkce_verifier')
|
|
}
|
|
|
|
export function clearPKCE(): void {
|
|
sessionStorage.removeItem('pkce_verifier')
|
|
}
|
|
|
|
export function storeToken(token: string): void {
|
|
localStorage.setItem('access_token', token)
|
|
}
|
|
|
|
export function getToken(): string | null {
|
|
return localStorage.getItem('access_token')
|
|
}
|
|
|
|
export function clearToken(): void {
|
|
localStorage.removeItem('access_token')
|
|
}
|