Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ SOLANA_RPC_URL=https://api.devnet.solana.com
# OBSERVABILITY_REDIS_QUEUE_KEYS=review:queue,events:pending

# Frontend
FRONTEND_URL=http://localhost:3000
FRONTEND_PORT=3000
VITE_API_URL=http://localhost:8000
VITE_GITHUB_CLIENT_ID=

# Deploy health-check URLs (set as GitHub repository variables, not secrets)
STAGING_HEALTH_URL=https://staging-api.solfoundry.org/health
Expand Down
24 changes: 22 additions & 2 deletions frontend/src/api/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,29 @@ export interface GitHubCallbackResponse extends AuthTokens {
user: User;
}

/**
* Get the GitHub OAuth authorize URL.
* Falls back to client-side construction when the backend is unavailable.
*/
export async function getGitHubAuthorizeUrl(): Promise<string> {
const data = await apiClient<{ authorize_url: string }>('/api/auth/github/authorize');
return data.authorize_url;
try {
const data = await apiClient<{ authorize_url: string }>('/api/auth/github/authorize');
return data.authorize_url;
} catch {
// Fallback: build the URL client-side using the Vite env var.
// This fixes the 404 when the backend (separate repo) isn't deployed.
const clientId = import.meta.env.VITE_GITHUB_CLIENT_ID;
if (!clientId) {
throw new Error('GitHub OAuth not configured. Set VITE_GITHUB_CLIENT_ID.');
}
const redirectUri = `${window.location.origin}/auth/github/callback`;
const state = Array.from(crypto.getRandomValues(new Uint8Array(32)))
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
// Store state for CSRF verification
sessionStorage.setItem('github_oauth_state', state);
return `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&scope=read:user&state=${state}`;
}
}

export async function exchangeGitHubCode(code: string, state?: string): Promise<GitHubCallbackResponse> {
Expand Down