fix: pass JWT token in WebSocket connection headers
WebSocket connections to /ws/agent were rejected by Kong (401) because the Authorization header was not included. Now reads access_token from secure storage and passes it in the WebSocket upgrade request headers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9cdc4933dc
commit
803cea0fe4
|
|
@ -31,7 +31,10 @@ class WebSocketClient {
|
|||
|
||||
final uri = Uri.parse('$baseUrl$path');
|
||||
try {
|
||||
_channel = WebSocketChannel.connect(uri);
|
||||
_channel = WebSocketChannel.connect(
|
||||
uri,
|
||||
headers: token != null ? {'Authorization': 'Bearer $token'} : null,
|
||||
);
|
||||
_isConnected = true;
|
||||
_reconnectAttempts = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,17 @@ class ChatRepositoryImpl implements ChatRepository {
|
|||
final ChatRemoteDatasource _remoteDatasource;
|
||||
final ChatLocalDatasource _localDatasource;
|
||||
final WebSocketClient _webSocketClient;
|
||||
final Future<String?> Function() _getAccessToken;
|
||||
|
||||
ChatRepositoryImpl({
|
||||
required ChatRemoteDatasource remoteDatasource,
|
||||
required ChatLocalDatasource localDatasource,
|
||||
required WebSocketClient webSocketClient,
|
||||
required Future<String?> Function() getAccessToken,
|
||||
}) : _remoteDatasource = remoteDatasource,
|
||||
_localDatasource = localDatasource,
|
||||
_webSocketClient = webSocketClient;
|
||||
_webSocketClient = webSocketClient,
|
||||
_getAccessToken = getAccessToken;
|
||||
|
||||
@override
|
||||
Stream<StreamEvent> sendMessage({
|
||||
|
|
@ -39,7 +42,8 @@ class ChatRepositoryImpl implements ChatRepository {
|
|||
final taskId = response['taskId'] as String? ?? response['task_id'] as String?;
|
||||
|
||||
// Connect to the agent WebSocket and subscribe to the session
|
||||
await _webSocketClient.connect('/ws/agent');
|
||||
final token = await _getAccessToken();
|
||||
await _webSocketClient.connect('/ws/agent', token: token);
|
||||
_webSocketClient.send({
|
||||
'event': 'subscribe_session',
|
||||
'data': {'sessionId': returnedSessionId, 'taskId': taskId},
|
||||
|
|
@ -87,7 +91,8 @@ class ChatRepositoryImpl implements ChatRepository {
|
|||
sessionId;
|
||||
final taskId = response['taskId'] as String? ?? response['task_id'] as String?;
|
||||
|
||||
await _webSocketClient.connect('/ws/agent');
|
||||
final voiceToken = await _getAccessToken();
|
||||
await _webSocketClient.connect('/ws/agent', token: voiceToken);
|
||||
_webSocketClient.send({
|
||||
'event': 'subscribe_session',
|
||||
'data': {'sessionId': returnedSessionId, 'taskId': taskId},
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../../../../core/network/dio_client.dart';
|
||||
import '../../../../core/network/websocket_client.dart';
|
||||
import '../../../auth/data/providers/auth_provider.dart';
|
||||
import '../../data/datasources/chat_local_datasource.dart';
|
||||
import '../../data/datasources/chat_remote_datasource.dart';
|
||||
import '../../data/models/chat_message_model.dart';
|
||||
|
|
@ -39,12 +40,14 @@ final chatRepositoryProvider = Provider<ChatRepository>((ref) {
|
|||
final remote = ref.watch(chatRemoteDatasourceProvider);
|
||||
final local = ref.watch(chatLocalDatasourceProvider);
|
||||
final ws = ref.watch(webSocketClientProvider);
|
||||
final storage = ref.watch(secureStorageProvider);
|
||||
|
||||
// Use a no-op local datasource if SharedPreferences is not yet ready
|
||||
return ChatRepositoryImpl(
|
||||
remoteDatasource: remote,
|
||||
localDatasource: local ?? _NoOpLocalDatasource(),
|
||||
webSocketClient: ws,
|
||||
getAccessToken: () => storage.read(key: 'access_token'),
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue