diff --git a/lib/features/authentication/data/datasources/keycloak_auth_service.dart b/lib/features/authentication/data/datasources/keycloak_auth_service.dart index f8e5899..f0626cc 100644 --- a/lib/features/authentication/data/datasources/keycloak_auth_service.dart +++ b/lib/features/authentication/data/datasources/keycloak_auth_service.dart @@ -119,6 +119,17 @@ class KeycloakAuthService { return null; } + /// Retourne un access token valide, en rafraîchissant automatiquement si expiré. + /// Utilisé par les datasources pour éviter d'envoyer un Bearer null ou expiré. + Future getValidAccessToken() async { + String? token = await _storage.read(key: _accessK); + if (token == null) return null; + if (JwtDecoder.isExpired(token)) { + token = await refreshToken(); + } + return token; + } + /// Récupération de l'utilisateur courant + Mapage Rôles Future getCurrentUser() async { String? token = await _storage.read(key: _accessK); diff --git a/lib/features/communication/data/datasources/messaging_remote_datasource.dart b/lib/features/communication/data/datasources/messaging_remote_datasource.dart index 2895e9c..fe1ecb2 100644 --- a/lib/features/communication/data/datasources/messaging_remote_datasource.dart +++ b/lib/features/communication/data/datasources/messaging_remote_datasource.dart @@ -4,10 +4,10 @@ library messaging_remote_datasource; import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:injectable/injectable.dart'; import '../../../../core/config/environment.dart'; import '../../../../core/error/exceptions.dart'; +import '../../../authentication/data/datasources/keycloak_auth_service.dart'; import '../models/message_model.dart'; import '../models/conversation_model.dart'; import '../../domain/entities/message.dart'; @@ -15,16 +15,16 @@ import '../../domain/entities/message.dart'; @lazySingleton class MessagingRemoteDatasource { final http.Client client; - final FlutterSecureStorage secureStorage; + final KeycloakAuthService authService; MessagingRemoteDatasource({ required this.client, - required this.secureStorage, + required this.authService, }); - /// Headers HTTP avec authentification + /// Headers HTTP avec authentification — rafraîchit le token si expiré (fix IC-03) Future> _getHeaders() async { - final token = await secureStorage.read(key: 'kc_access'); + final token = await authService.getValidAccessToken(); return { 'Content-Type': 'application/json', 'Accept': 'application/json', diff --git a/lib/features/finance_workflow/data/datasources/finance_workflow_remote_datasource.dart b/lib/features/finance_workflow/data/datasources/finance_workflow_remote_datasource.dart index e93538f..4bb0ed6 100644 --- a/lib/features/finance_workflow/data/datasources/finance_workflow_remote_datasource.dart +++ b/lib/features/finance_workflow/data/datasources/finance_workflow_remote_datasource.dart @@ -3,26 +3,26 @@ library finance_workflow_remote_datasource; import 'dart:convert'; import 'package:http/http.dart' as http; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:injectable/injectable.dart'; import '../../../../core/config/environment.dart'; import '../../../../core/error/exceptions.dart'; +import '../../../authentication/data/datasources/keycloak_auth_service.dart'; import '../models/transaction_approval_model.dart'; import '../models/budget_model.dart'; @lazySingleton class FinanceWorkflowRemoteDatasource { final http.Client client; - final FlutterSecureStorage secureStorage; + final KeycloakAuthService authService; FinanceWorkflowRemoteDatasource({ required this.client, - required this.secureStorage, + required this.authService, }); - /// Headers HTTP avec authentification + /// Headers HTTP avec authentification — rafraîchit le token si expiré (fix IC-03) Future> _getHeaders() async { - final token = await secureStorage.read(key: 'kc_access'); + final token = await authService.getValidAccessToken(); return { 'Content-Type': 'application/json', 'Accept': 'application/json',