|
|
<script> |
|
|
import { onMount } from 'svelte'; |
|
|
import { goto } from '$app/navigation'; |
|
|
import { page } from '$app/stores'; |
|
|
|
|
|
let status = 'Processing...'; |
|
|
let error = null; |
|
|
|
|
|
onMount(async () => { |
|
|
try { |
|
|
const code = $page.url.searchParams.get('code'); |
|
|
const state = $page.url.searchParams.get('state'); |
|
|
const errorParam = $page.url.searchParams.get('error'); |
|
|
const errorDescription = $page.url.searchParams.get('error_description'); |
|
|
|
|
|
if (errorParam) { |
|
|
error = errorDescription || errorParam; |
|
|
status = 'Authentication failed'; |
|
|
return; |
|
|
} |
|
|
|
|
|
if (!code) { |
|
|
error = 'No authorization code received'; |
|
|
status = 'Authentication failed'; |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
const storedState = sessionStorage.getItem('oauth_state'); |
|
|
if (storedState && state !== storedState) { |
|
|
error = 'Invalid state parameter'; |
|
|
status = 'Authentication failed'; |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
const tokenResponse = await fetch('/api/auth/token', { |
|
|
method: 'POST', |
|
|
headers: { |
|
|
'Content-Type': 'application/json', |
|
|
}, |
|
|
body: JSON.stringify({ code }), |
|
|
}); |
|
|
|
|
|
if (!tokenResponse.ok) { |
|
|
const errorText = await tokenResponse.text(); |
|
|
console.error('Token exchange failed:', errorText); |
|
|
throw new Error(`Failed to exchange code for token: ${errorText}`); |
|
|
} |
|
|
|
|
|
const tokenData = await tokenResponse.json(); |
|
|
|
|
|
|
|
|
localStorage.setItem('hf_access_token', tokenData.access_token); |
|
|
|
|
|
status = 'Successfully authenticated!'; |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
goto('/'); |
|
|
}, 2000); |
|
|
|
|
|
} catch (err) { |
|
|
error = err.message; |
|
|
status = 'Authentication failed'; |
|
|
} |
|
|
}); |
|
|
</script> |
|
|
|
|
|
<svelte:head> |
|
|
<title>Authenticating with Hugging Face - HFStudio</title> |
|
|
</svelte:head> |
|
|
|
|
|
<div class="min-h-screen flex items-center justify-center bg-gray-50"> |
|
|
<div class="max-w-md w-full bg-white rounded-lg shadow-md p-6"> |
|
|
<div class="text-center"> |
|
|
<img src="/assets/hf-logo.png" alt="HF Logo" class="w-12 h-12 mx-auto mb-4" /> |
|
|
<h1 class="text-xl font-semibold mb-2">HFStudio Authentication</h1> |
|
|
|
|
|
{#if error} |
|
|
<div class="text-red-600 mb-4"> |
|
|
<p class="font-medium">{status}</p> |
|
|
<p class="text-sm mt-1">{error}</p> |
|
|
</div> |
|
|
<button |
|
|
on:click={() => goto('/')} |
|
|
class="px-4 py-2 bg-gradient-to-r from-amber-400 to-orange-500 text-white rounded-lg hover:from-amber-500 hover:to-orange-600 transition-colors" |
|
|
> |
|
|
Return to HFStudio |
|
|
</button> |
|
|
{:else} |
|
|
<div class="text-gray-600 mb-4"> |
|
|
<div class="animate-spin w-8 h-8 border-2 border-amber-400 border-t-transparent rounded-full mx-auto mb-2"></div> |
|
|
<p>{status}</p> |
|
|
</div> |
|
|
{/if} |
|
|
</div> |
|
|
</div> |
|
|
</div> |