From ce6a5a80d7cdaae422ea794a4f178204e591c932 Mon Sep 17 00:00:00 2001 From: Job Guldemeester Date: Thu, 14 Mar 2024 16:44:30 +0100 Subject: [PATCH 1/3] :memo: Updated documentation about grants --- lib/src/oauth_chopper.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/src/oauth_chopper.dart b/lib/src/oauth_chopper.dart index 3427df1..cf75846 100644 --- a/lib/src/oauth_chopper.dart +++ b/lib/src/oauth_chopper.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:oauth2/oauth2.dart'; +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'; @@ -73,13 +73,13 @@ class OAuthChopper { 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); await _storage.saveCredentials(newCredentials.toJson()); return OAuthToken.fromCredentials(newCredentials); - } on AuthorizationException { + } on oauth2.AuthorizationException { _storage.clear(); rethrow; } @@ -89,7 +89,7 @@ class OAuthChopper { /// Currently supported grants: /// - [ResourceOwnerPasswordGrant] /// - [ClientCredentialsGrant] - /// + /// - [AuthorizationCodeGrant] /// Throws an exception if the grant fails. Future requestGrant(OAuthGrant grant) async { final credentials = From 54d2d4fe0841ccc57ebf4ab3dc0c581ddc7091f2 Mon Sep 17 00:00:00 2001 From: Job Guldemeester Date: Thu, 14 Mar 2024 16:55:24 +0100 Subject: [PATCH 2/3] :sparkles: Added passing of custom http client --- lib/src/oauth_chopper.dart | 19 +++++++++++------- lib/src/oauth_grant.dart | 37 ++++++++++++++++++++++++++---------- pubspec.yaml | 2 +- test/oauth_chopper_test.dart | 4 ++-- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/lib/src/oauth_chopper.dart b/lib/src/oauth_chopper.dart index cf75846..a914acf 100644 --- a/lib/src/oauth_chopper.dart +++ b/lib/src/oauth_chopper.dart @@ -1,5 +1,6 @@ import 'dart:async'; +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'; @@ -36,11 +37,15 @@ 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; + OAuthChopper({ required this.authorizationEndpoint, 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]. For persisting the credentials implement a custom [OAuthStorage]. @@ -51,9 +56,7 @@ class OAuthChopper { /// Get stored [OAuthToken]. Future get token async { final credentialsJson = await _storage.fetchCredentials(); - return credentialsJson != null - ? OAuthToken.fromJson(credentialsJson) - : null; + return credentialsJson != null ? OAuthToken.fromJson(credentialsJson) : null; } /// Provides an [OAuthAuthenticator] instance. @@ -75,8 +78,11 @@ class OAuthChopper { if (credentialsJson == null) return null; 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 oauth2.AuthorizationException { @@ -92,8 +98,7 @@ class OAuthChopper { /// - [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 b7f56a3..3ee43d7 100644 --- a/lib/src/oauth_grant.dart +++ b/lib/src/oauth_grant.dart @@ -1,10 +1,15 @@ +import 'package:http/http.dart' as http; import 'package:oauth2/oauth2.dart' as oauth; abstract class OAuthGrant { const OAuthGrant(); Future handle( - Uri authorizationEndpoint, String identifier, String secret); + Uri authorizationEndpoint, + String identifier, + String secret, + http.Client? httpClient, + ); } /// Obtains credentials using a [resource owner password grant](https://tools.ietf.org/html/rfc6749#section-1.3.3). @@ -12,18 +17,22 @@ class ResourceOwnerPasswordGrant extends OAuthGrant { final String username; final String password; - const ResourceOwnerPasswordGrant( - {required this.username, required this.password}); + const ResourceOwnerPasswordGrant({required this.username, required this.password}); @override Future handle( - Uri authorizationEndpoint, String identifier, String secret) async { + Uri authorizationEndpoint, + String identifier, + String secret, + http.Client? httpClient, + ) async { final client = await oauth.resourceOwnerPasswordGrant( authorizationEndpoint, username, password, secret: secret, identifier: identifier, + httpClient: httpClient, ); return client.credentials.toJson(); } @@ -35,11 +44,16 @@ class ClientCredentialsGrant extends OAuthGrant { @override Future handle( - Uri authorizationEndpoint, String identifier, String secret) async { + Uri authorizationEndpoint, + String identifier, + String secret, + http.Client? httpClient, + ) async { final client = await oauth.clientCredentialsGrant( authorizationEndpoint, identifier, secret, + httpClient: httpClient, ); return client.credentials.toJson(); } @@ -63,18 +77,21 @@ class AuthorizationCodeGrant extends OAuthGrant { @override Future handle( - Uri authorizationEndpoint, String identifier, String secret) async { + Uri authorizationEndpoint, + String identifier, + String secret, + http.Client? httpClient, + ) async { final grant = oauth.AuthorizationCodeGrant( identifier, authorizationEndpoint, tokenEndpoint, + httpClient: httpClient, ); - var authorizationUrl = - grant.getAuthorizationUrl(redirectUrl, scopes: scopes); + var authorizationUrl = grant.getAuthorizationUrl(redirectUrl, scopes: scopes); await redirect(authorizationUrl); var responseUrl = await listen(redirectUrl); - oauth.Client client = - await grant.handleAuthorizationResponse(responseUrl.queryParameters); + oauth.Client client = await grant.handleAuthorizationResponse(responseUrl.queryParameters); return client.credentials.toJson(); } diff --git a/pubspec.yaml b/pubspec.yaml index d6585a4..0b60b20 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 lints: ">=2.1.1 <4.0.0" mocktail: ^1.0.3 test: ^1.25.2 diff --git a/test/oauth_chopper_test.dart b/test/oauth_chopper_test.dart index 93fa29d..c83c067 100644 --- a/test/oauth_chopper_test.dart +++ b/test/oauth_chopper_test.dart @@ -89,7 +89,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'), @@ -101,7 +101,7 @@ 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'); From d4c88250f560dfc10198c64db78fc4de8c66f0ca Mon Sep 17 00:00:00 2001 From: Job Guldemeester Date: Thu, 14 Mar 2024 17:01:09 +0100 Subject: [PATCH 3/3] :art: Formatted code --- lib/src/oauth_chopper.dart | 7 +++++-- lib/src/oauth_grant.dart | 9 ++++++--- test/oauth_chopper_test.dart | 3 ++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/src/oauth_chopper.dart b/lib/src/oauth_chopper.dart index a914acf..eeac01b 100644 --- a/lib/src/oauth_chopper.dart +++ b/lib/src/oauth_chopper.dart @@ -56,7 +56,9 @@ class OAuthChopper { /// Get stored [OAuthToken]. Future get token async { final credentialsJson = await _storage.fetchCredentials(); - return credentialsJson != null ? OAuthToken.fromJson(credentialsJson) : null; + return credentialsJson != null + ? OAuthToken.fromJson(credentialsJson) + : null; } /// Provides an [OAuthAuthenticator] instance. @@ -98,7 +100,8 @@ class OAuthChopper { /// - [AuthorizationCodeGrant] /// Throws an exception if the grant fails. Future requestGrant(OAuthGrant grant) async { - final credentials = await grant.handle(authorizationEndpoint, identifier, secret, httpClient); + 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 3ee43d7..4f1933a 100644 --- a/lib/src/oauth_grant.dart +++ b/lib/src/oauth_grant.dart @@ -17,7 +17,8 @@ class ResourceOwnerPasswordGrant extends OAuthGrant { final String username; final String password; - const ResourceOwnerPasswordGrant({required this.username, required this.password}); + const ResourceOwnerPasswordGrant( + {required this.username, required this.password}); @override Future handle( @@ -88,10 +89,12 @@ class AuthorizationCodeGrant extends OAuthGrant { tokenEndpoint, httpClient: httpClient, ); - var authorizationUrl = grant.getAuthorizationUrl(redirectUrl, scopes: scopes); + var authorizationUrl = + grant.getAuthorizationUrl(redirectUrl, scopes: scopes); await redirect(authorizationUrl); var responseUrl = await listen(redirectUrl); - oauth.Client client = await grant.handleAuthorizationResponse(responseUrl.queryParameters); + oauth.Client client = + await grant.handleAuthorizationResponse(responseUrl.queryParameters); return client.credentials.toJson(); } diff --git a/test/oauth_chopper_test.dart b/test/oauth_chopper_test.dart index c83c067..33d8f36 100644 --- a/test/oauth_chopper_test.dart +++ b/test/oauth_chopper_test.dart @@ -101,7 +101,8 @@ void main() { final token = await oauthChopper.requestGrant(grantMock); // assert - verify(() => grantMock.handle(any(), 'identifier', 'secret', null)).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');