diff --git a/packages/better_networking/lib/services/http_client_manager.dart b/packages/better_networking/lib/services/http_client_manager.dart index 3d8430c5..3dbc1a09 100644 --- a/packages/better_networking/lib/services/http_client_manager.dart +++ b/packages/better_networking/lib/services/http_client_manager.dart @@ -10,6 +10,23 @@ http.Client createHttpClientWithNoSSL() { return IOClient(ioClient); } +class _JsonAcceptClient extends http.BaseClient { + final http.Client _inner; + + _JsonAcceptClient(this._inner); + + @override + Future send(http.BaseRequest request) { + request.headers['Accept'] = 'application/json'; + return _inner.send(request); + } + + @override + void close() { + _inner.close(); + } +} + class HttpClientManager { static final HttpClientManager _instance = HttpClientManager._internal(); static const int _maxCancelledRequests = 100; @@ -60,4 +77,17 @@ class HttpClientManager { bool hasActiveClient(String requestId) { return _clients.containsKey(requestId); } + + http.Client createClientWithJsonAccept( + String requestId, { + bool noSSL = false, + }) { + final baseClient = (noSSL && !kIsWeb) + ? createHttpClientWithNoSSL() + : http.Client(); + + final client = _JsonAcceptClient(baseClient); + _clients[requestId] = client; + return client; + } } diff --git a/packages/better_networking/lib/utils/auth/oauth2_utils.dart b/packages/better_networking/lib/utils/auth/oauth2_utils.dart index d0370efb..3516e9b9 100644 --- a/packages/better_networking/lib/utils/auth/oauth2_utils.dart +++ b/packages/better_networking/lib/utils/auth/oauth2_utils.dart @@ -5,6 +5,7 @@ import 'package:flutter_web_auth_2/flutter_web_auth_2.dart'; import 'package:oauth2/oauth2.dart' as oauth2; import '../../models/models.dart'; +import '../../services/http_client_manager.dart'; Future oAuth2AuthorizationCodeGrantHandler({ required String identifier, @@ -36,11 +37,17 @@ Future oAuth2AuthorizationCodeGrantHandler({ } } + // Create a unique request ID for this OAuth flow + final requestId = 'oauth2-${DateTime.now().millisecondsSinceEpoch}'; + final httpClientManager = HttpClientManager(); + final baseClient = httpClientManager.createClientWithJsonAccept(requestId); + final grant = oauth2.AuthorizationCodeGrant( identifier, authorizationEndpoint, tokenEndpoint, secret: secret, + httpClient: baseClient, ); final authorizationUrl = grant.getAuthorizationUrl( @@ -58,21 +65,26 @@ Future oAuth2AuthorizationCodeGrantHandler({ ); try { + // Use standard oauth2 package for other providers final client = await grant.handleAuthorizationResponse( Uri.parse(uri).queryParameters, ); log('OAuth2 authorization successful, saving credentials'); - await credentialsFile.writeAsString(client.credentials.toJson()); log(client.credentials.toJson()); + // Clean up the HTTP client + httpClientManager.closeClient(requestId); + return client; } catch (e) { log('Error handling authorization response: $e'); - log('URI query parameters: ${Uri.parse(uri).queryParameters}'); + // Clean up the HTTP client on error + httpClientManager.closeClient(requestId); + rethrow; } } @@ -102,28 +114,43 @@ Future oAuth2ClientCredentialsGrantHandler({ log("Creating Client with id: ${oauth2Model.clientId}"); log("Creating Client with sec: ${oauth2Model.clientSecret}"); - // Otherwise, perform the client credentials grant - final client = await oauth2.clientCredentialsGrant( - Uri.parse(oauth2Model.accessTokenUrl), - oauth2Model.clientId, - oauth2Model.clientSecret, - scopes: oauth2Model.scope != null ? [oauth2Model.scope!] : null, - basicAuth: false, - ); - log("Created Client with id: ${client.identifier}"); - log("Created Client with sec: ${client.secret}"); - log("Created Client with sec: ${client.credentials.toJson()}"); - - log('Successfully authenticated via client credentials grant'); + // Create a unique request ID for this OAuth flow + final requestId = 'oauth2-client-${DateTime.now().millisecondsSinceEpoch}'; + final httpClientManager = HttpClientManager(); + final baseClient = httpClientManager.createClientWithJsonAccept(requestId); try { - await credentialsFile.writeAsString(client.credentials.toJson()); - log('Saved credentials to file'); - } catch (e) { - log('Failed to save credentials: $e'); - } + // Otherwise, perform the client credentials grant + final client = await oauth2.clientCredentialsGrant( + Uri.parse(oauth2Model.accessTokenUrl), + oauth2Model.clientId, + oauth2Model.clientSecret, + scopes: oauth2Model.scope != null ? [oauth2Model.scope!] : null, + basicAuth: false, + httpClient: baseClient, + ); + log("Created Client with id: ${client.identifier}"); + log("Created Client with sec: ${client.secret}"); + log("Created Client with sec: ${client.credentials.toJson()}"); - return client; + log('Successfully authenticated via client credentials grant'); + + try { + await credentialsFile.writeAsString(client.credentials.toJson()); + log('Saved credentials to file'); + } catch (e) { + log('Failed to save credentials: $e'); + } + + // Clean up the HTTP client + httpClientManager.closeClient(requestId); + + return client; + } catch (e) { + // Clean up the HTTP client on error + httpClientManager.closeClient(requestId); + rethrow; + } } Future oAuth2ResourceOwnerPasswordGrantHandler({ @@ -155,28 +182,43 @@ Future oAuth2ResourceOwnerPasswordGrantHandler({ log("Creating Client with id: ${oauth2Model.clientId}"); log("Creating Client with sec: ${oauth2Model.clientSecret}"); - // Otherwise, perform the owner password grant - final client = await oauth2.resourceOwnerPasswordGrant( - Uri.parse(oauth2Model.accessTokenUrl), - oauth2Model.username!, - oauth2Model.password!, - identifier: oauth2Model.clientId, - secret: oauth2Model.clientSecret, - scopes: oauth2Model.scope != null ? [oauth2Model.scope!] : null, - basicAuth: false, - ); - log("Created Client with id: ${client.identifier}"); - log("Created Client with sec: ${client.secret}"); - log("Created Client with sec: ${client.credentials.toJson()}"); - - log('Successfully authenticated via client credentials grant'); + // Create a unique request ID for this OAuth flow + final requestId = 'oauth2-password-${DateTime.now().millisecondsSinceEpoch}'; + final httpClientManager = HttpClientManager(); + final baseClient = httpClientManager.createClientWithJsonAccept(requestId); try { - await credentialsFile.writeAsString(client.credentials.toJson()); - log('Saved credentials to file'); - } catch (e) { - log('Failed to save credentials: $e'); - } + // Otherwise, perform the owner password grant + final client = await oauth2.resourceOwnerPasswordGrant( + Uri.parse(oauth2Model.accessTokenUrl), + oauth2Model.username!, + oauth2Model.password!, + identifier: oauth2Model.clientId, + secret: oauth2Model.clientSecret, + scopes: oauth2Model.scope != null ? [oauth2Model.scope!] : null, + basicAuth: false, + httpClient: baseClient, + ); + log("Created Client with id: ${client.identifier}"); + log("Created Client with sec: ${client.secret}"); + log("Created Client with sec: ${client.credentials.toJson()}"); - return client; + log('Successfully authenticated via client credentials grant'); + + try { + await credentialsFile.writeAsString(client.credentials.toJson()); + log('Saved credentials to file'); + } catch (e) { + log('Failed to save credentials: $e'); + } + + // Clean up the HTTP client + httpClientManager.closeClient(requestId); + + return client; + } catch (e) { + // Clean up the HTTP client on error + httpClientManager.closeClient(requestId); + rethrow; + } }