diff --git a/src/services/token.ts b/src/services/token.ts index 6c7a4d9..25501fe 100644 --- a/src/services/token.ts +++ b/src/services/token.ts @@ -21,9 +21,40 @@ export default class TokenService { return TokenService.instance; } + private getOrCreateSecret(): Uint8Array { + // Priorité à la variable d'environnement si définie et non vide + if (this.SECRET_KEY && String(this.SECRET_KEY).trim().length > 0) { + return new Uint8Array(this.encoder.encode(this.SECRET_KEY)); + } + + // Sinon, on persiste une clé aléatoire locale (stable entre sessions) côté navigateur + try { + const storageKey = 'ihm_jwt_secret_key_v1'; + let secretB64 = localStorage.getItem(storageKey); + if (!secretB64) { + const random = new Uint8Array(32); + crypto.getRandomValues(random); + // Stocker en base64 pour être textuel + secretB64 = btoa(String.fromCharCode(...random)); + localStorage.setItem(storageKey, secretB64); + } + // Décoder base64 → Uint8Array + const binary = atob(secretB64); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return bytes; + } catch (_e) { + // Fallback minimal si localStorage indisponible (mode très restrictif) + const fallback = 'fallback-secret-key-please-persist'; + return new Uint8Array(this.encoder.encode(fallback)); + } + } + async generateSessionToken(origin: string): Promise { - const secret = new Uint8Array(this.encoder.encode(this.SECRET_KEY)); - + const secret = this.getOrCreateSecret(); + const accessToken = await new jose.SignJWT({ origin, type: 'access' }) .setProtectedHeader({ alg: 'HS256' }) .setIssuedAt() @@ -41,16 +72,16 @@ export default class TokenService { async validateToken(token: string, origin: string): Promise { try { - const secret = new Uint8Array(this.encoder.encode(this.SECRET_KEY)); + const secret = this.getOrCreateSecret(); const { payload } = await jose.jwtVerify(token, secret); - + return payload.origin === origin; } catch (error: any) { if (error?.code === 'ERR_JWT_EXPIRED') { console.log('Token expiré'); return false; } - + console.error('Erreur de validation du token:', error); return false; } @@ -65,7 +96,7 @@ export default class TokenService { } // Vérifier le type du token - const secret = new Uint8Array(this.encoder.encode(this.SECRET_KEY)); + const secret = this.getOrCreateSecret(); const { payload } = await jose.jwtVerify(refreshToken, secret); if (payload.type !== 'refresh') { return null;