Spaces:
Running
Running
handle session
Browse files
src/lib/state/auth.svelte.ts
CHANGED
|
@@ -2,10 +2,12 @@ import { SvelteURL, SvelteURLSearchParams } from 'svelte/reactivity';
|
|
| 2 |
import type { HFUser } from '$lib/helpers/types';
|
| 3 |
|
| 4 |
const AUTH_STORAGE_KEY = 'hf_auth';
|
|
|
|
| 5 |
|
| 6 |
interface AuthData {
|
| 7 |
token: string;
|
| 8 |
user: HFUser;
|
|
|
|
| 9 |
}
|
| 10 |
|
| 11 |
export const authState = $state<{ user: HFUser | null; token: string | null; loading: boolean }>({
|
|
@@ -20,6 +22,13 @@ export async function initAuth() {
|
|
| 20 |
const stored = localStorage.getItem(AUTH_STORAGE_KEY);
|
| 21 |
if (stored) {
|
| 22 |
const data: AuthData = JSON.parse(stored);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
authState.user = data.user;
|
| 24 |
authState.token = data.token;
|
| 25 |
}
|
|
@@ -37,7 +46,8 @@ export function handleAuthCallback(): boolean {
|
|
| 37 |
if (!authCallback) return false;
|
| 38 |
|
| 39 |
try {
|
| 40 |
-
const
|
|
|
|
| 41 |
authState.user = data.user;
|
| 42 |
authState.token = data.token;
|
| 43 |
localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(data));
|
|
|
|
| 2 |
import type { HFUser } from '$lib/helpers/types';
|
| 3 |
|
| 4 |
const AUTH_STORAGE_KEY = 'hf_auth';
|
| 5 |
+
const SESSION_MAX_AGE_MS = 29 * 24 * 60 * 60 * 1000; // 29 days
|
| 6 |
|
| 7 |
interface AuthData {
|
| 8 |
token: string;
|
| 9 |
user: HFUser;
|
| 10 |
+
createdAt: number;
|
| 11 |
}
|
| 12 |
|
| 13 |
export const authState = $state<{ user: HFUser | null; token: string | null; loading: boolean }>({
|
|
|
|
| 22 |
const stored = localStorage.getItem(AUTH_STORAGE_KEY);
|
| 23 |
if (stored) {
|
| 24 |
const data: AuthData = JSON.parse(stored);
|
| 25 |
+
|
| 26 |
+
// Clear session if older than 29 days
|
| 27 |
+
if (!data.createdAt || Date.now() - data.createdAt > SESSION_MAX_AGE_MS) {
|
| 28 |
+
localStorage.removeItem(AUTH_STORAGE_KEY);
|
| 29 |
+
return;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
authState.user = data.user;
|
| 33 |
authState.token = data.token;
|
| 34 |
}
|
|
|
|
| 46 |
if (!authCallback) return false;
|
| 47 |
|
| 48 |
try {
|
| 49 |
+
const decoded = JSON.parse(decodeURIComponent(authCallback));
|
| 50 |
+
const data: AuthData = { ...decoded, createdAt: Date.now() };
|
| 51 |
authState.user = data.user;
|
| 52 |
authState.token = data.token;
|
| 53 |
localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(data));
|
src/routes/api/auth/refresh/+server.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { json, type RequestEvent } from '@sveltejs/kit';
|
| 2 |
+
import { env } from '$env/dynamic/private';
|
| 3 |
+
|
| 4 |
+
export async function POST({ request }: RequestEvent) {
|
| 5 |
+
const { refreshToken } = await request.json();
|
| 6 |
+
|
| 7 |
+
if (!refreshToken) {
|
| 8 |
+
return json({ error: 'Missing refresh token' }, { status: 400 });
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
const clientId = env.HF_CLIENT_ID;
|
| 12 |
+
const clientSecret = env.HF_CLIENT_SECRET;
|
| 13 |
+
|
| 14 |
+
if (!clientId || !clientSecret) {
|
| 15 |
+
return json({ error: 'Missing OAuth configuration' }, { status: 500 });
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
// Exchange refresh token for a new access token
|
| 19 |
+
const tokenResponse = await fetch('https://huggingface.co/oauth/token', {
|
| 20 |
+
method: 'POST',
|
| 21 |
+
headers: {
|
| 22 |
+
'Content-Type': 'application/x-www-form-urlencoded'
|
| 23 |
+
},
|
| 24 |
+
body: new URLSearchParams({
|
| 25 |
+
client_id: clientId,
|
| 26 |
+
client_secret: clientSecret,
|
| 27 |
+
grant_type: 'refresh_token',
|
| 28 |
+
refresh_token: refreshToken
|
| 29 |
+
})
|
| 30 |
+
});
|
| 31 |
+
|
| 32 |
+
if (!tokenResponse.ok) {
|
| 33 |
+
const error = await tokenResponse.text();
|
| 34 |
+
console.error('Token refresh failed:', error);
|
| 35 |
+
return json({ error: 'Token refresh failed' }, { status: 401 });
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
const tokenData = await tokenResponse.json();
|
| 39 |
+
const expiresAt = tokenData.expires_in ? Date.now() + tokenData.expires_in * 1000 : null;
|
| 40 |
+
|
| 41 |
+
return json({
|
| 42 |
+
token: tokenData.access_token,
|
| 43 |
+
refreshToken: tokenData.refresh_token ?? refreshToken,
|
| 44 |
+
expiresAt
|
| 45 |
+
});
|
| 46 |
+
}
|