diff --git a/lib/src/oauth_chopper.dart b/lib/src/oauth_chopper.dart index 0d35e0b..6367ac3 100644 --- a/lib/src/oauth_chopper.dart +++ b/lib/src/oauth_chopper.dart @@ -1,6 +1,7 @@ import 'dart:async'; -import 'package:oauth2/oauth2.dart'; +import 'package:http/http.dart' as http; +import 'package:oauth2/oauth2.dart' as oauth2; import 'package:oauth_chopper/src/oauth_authenticator.dart'; import 'package:oauth_chopper/src/oauth_grant.dart'; import 'package:oauth_chopper/src/oauth_interceptor.dart'; @@ -27,6 +28,7 @@ class OAuthChopper { required this.identifier, required this.secret, this.endSessionEndpoint, + this.httpClient, /// OAuth storage for storing credentials. /// By default it will use a in memory storage [MemoryStorage]. @@ -53,6 +55,10 @@ class OAuthChopper { /// See [OAuthStorage] for more information. final OAuthStorage _storage; + /// Provide a custom [http.Client] which will be passed to [oauth2] and used + /// for making new requests. + final http.Client? httpClient; + /// Get stored [OAuthToken]. Future get token async { final credentialsJson = await _storage.fetchCredentials(); @@ -76,18 +82,21 @@ class OAuthChopper { /// Tries to refresh the available credentials and returns a new [OAuthToken] /// instance. /// Throws an exception when refreshing fails. If the exception is a - /// [AuthorizationException] it clears the storage. - /// See [Credentials.refresh] + /// [oauth2.AuthorizationException] it clears the storage. + /// See [oauth2.Credentials.refresh] Future refresh() async { final credentialsJson = await _storage.fetchCredentials(); if (credentialsJson == null) return null; - final credentials = Credentials.fromJson(credentialsJson); + final credentials = oauth2.Credentials.fromJson(credentialsJson); try { - final newCredentials = - await credentials.refresh(identifier: identifier, secret: secret); + final newCredentials = await credentials.refresh( + identifier: identifier, + secret: secret, + httpClient: httpClient, + ); await _storage.saveCredentials(newCredentials.toJson()); return OAuthToken.fromCredentials(newCredentials); - } on AuthorizationException { + } on oauth2.AuthorizationException { _storage.clear(); rethrow; } @@ -99,11 +108,15 @@ class OAuthChopper { /// Currently supported grants: /// - [ResourceOwnerPasswordGrant] /// - [ClientCredentialsGrant] - /// + /// - [AuthorizationCodeGrant] /// Throws an exception if the grant fails. Future requestGrant(OAuthGrant grant) async { - final credentials = - await grant.handle(authorizationEndpoint, identifier, secret); + final credentials = await grant.handle( + authorizationEndpoint, + identifier, + secret, + httpClient, + ); await _storage.saveCredentials(credentials); diff --git a/lib/src/oauth_grant.dart b/lib/src/oauth_grant.dart index 3faa6ea..6392951 100644 --- a/lib/src/oauth_grant.dart +++ b/lib/src/oauth_grant.dart @@ -1,3 +1,4 @@ +import 'package:http/http.dart' as http; import 'package:oauth2/oauth2.dart' as oauth; /// {@template oauth_grant} @@ -13,6 +14,7 @@ abstract interface class OAuthGrant { Uri authorizationEndpoint, String identifier, String secret, + http.Client? httpClient, ); } @@ -40,6 +42,7 @@ class ResourceOwnerPasswordGrant implements OAuthGrant { Uri authorizationEndpoint, String identifier, String secret, + http.Client? httpClient, ) async { final client = await oauth.resourceOwnerPasswordGrant( authorizationEndpoint, @@ -47,6 +50,7 @@ class ResourceOwnerPasswordGrant implements OAuthGrant { password, secret: secret, identifier: identifier, + httpClient: httpClient, ); return client.credentials.toJson(); } @@ -64,11 +68,13 @@ class ClientCredentialsGrant implements OAuthGrant { Uri authorizationEndpoint, String identifier, String secret, + http.Client? httpClient, ) async { final client = await oauth.clientCredentialsGrant( authorizationEndpoint, identifier, secret, + httpClient: httpClient, ); return client.credentials.toJson(); } @@ -113,11 +119,13 @@ class AuthorizationCodeGrant implements OAuthGrant { Uri authorizationEndpoint, String identifier, String secret, + http.Client? httpClient, ) async { final grant = oauth.AuthorizationCodeGrant( identifier, authorizationEndpoint, tokenEndpoint, + httpClient: httpClient, ); final authorizationUrl = grant.getAuthorizationUrl( diff --git a/pubspec.yaml b/pubspec.yaml index f5aa0d4..9b8db55 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,10 +8,10 @@ environment: dependencies: chopper: ^7.2.0 + http: ^1.2.1 oauth2: ^2.0.2 dev_dependencies: - http: ^1.2.1 mocktail: ^1.0.3 test: ^1.25.2 very_good_analysis: ^5.1.0 diff --git a/test/oauth_chopper_test.dart b/test/oauth_chopper_test.dart index c529568..ce728b9 100644 --- a/test/oauth_chopper_test.dart +++ b/test/oauth_chopper_test.dart @@ -93,7 +93,7 @@ void main() { test('Successful grant is stored', () async { // arrange when(() => storageMock.saveCredentials(any())).thenAnswer((_) => null); - when(() => grantMock.handle(any(), any(), any())) + when(() => grantMock.handle(any(), any(), any(), null)) .thenAnswer((_) async => testJson); final oauthChopper = OAuthChopper( authorizationEndpoint: Uri.parse('endpoint'), @@ -106,7 +106,8 @@ void main() { final token = await oauthChopper.requestGrant(grantMock); // assert - verify(() => grantMock.handle(any(), 'identifier', 'secret')).called(1); + verify(() => grantMock.handle(any(), 'identifier', 'secret', null)) + .called(1); verify(() => storageMock.saveCredentials(testJson)).called(1); expect(token.accessToken, 'accesToken'); expect(token.idToken, 'idToken');