add `onCredentialsRefreshed` parameter to `AuthorizationCodeGrant`
diff --git a/lib/src/authorization_code_grant.dart b/lib/src/authorization_code_grant.dart
index 6b28290..526ab9f 100644
--- a/lib/src/authorization_code_grant.dart
+++ b/lib/src/authorization_code_grant.dart
@@ -9,6 +9,7 @@
import 'client.dart';
import 'authorization_exception.dart';
+import 'credentials.dart';
import 'handle_access_token_response.dart';
import 'parameters.dart';
import 'utils.dart';
@@ -71,6 +72,11 @@
/// documentation.
final Uri tokenEndpoint;
+ /// Callback to be invoked whenever the credentials are refreshed.
+ ///
+ /// This will be passed as-is to the constructed [Client].
+ CredentialsRefreshedCallback _onCredentialsRefreshed;
+
/// Whether to use HTTP Basic authentication for authorizing the client.
final bool _basicAuth;
@@ -107,6 +113,9 @@
/// [httpClient] is used for all HTTP requests made by this grant, as well as
/// those of the [Client] is constructs.
///
+ /// [onCredentialsRefreshed] will be called by the constructed [Client]
+ /// whenever the credentials are refreshed.
+ ///
/// The scope strings will be separated by the provided [delimiter]. This
/// defaults to `" "`, the OAuth2 standard, but some APIs (such as Facebook's)
/// use non-standard delimiters.
@@ -126,11 +135,13 @@
String delimiter,
bool basicAuth = true,
http.Client httpClient,
+ CredentialsRefreshedCallback onCredentialsRefreshed,
Map<String, dynamic> getParameters(MediaType contentType, String body)})
: _basicAuth = basicAuth,
_httpClient = httpClient == null ? new http.Client() : httpClient,
_delimiter = delimiter ?? ' ',
- _getParameters = getParameters ?? parseJsonParameters;
+ _getParameters = getParameters ?? parseJsonParameters,
+ _onCredentialsRefreshed = onCredentialsRefreshed;
/// Returns the URL to which the resource owner should be redirected to
/// authorize this client.
@@ -289,7 +300,8 @@
identifier: this.identifier,
secret: this.secret,
basicAuth: _basicAuth,
- httpClient: _httpClient);
+ httpClient: _httpClient,
+ onCredentialsRefreshed: _onCredentialsRefreshed);
}
/// Closes the grant and frees its resources.
diff --git a/test/authorization_code_grant_test.dart b/test/authorization_code_grant_test.dart
index ec6e71b..babdb78 100644
--- a/test/authorization_code_grant_test.dart
+++ b/test/authorization_code_grant_test.dart
@@ -289,4 +289,50 @@
})));
});
});
+
+ group('onCredentialsRefreshed', () {
+ test('is correctly propagated', () async {
+ var isCallbackInvoked = false;
+ var grant = new oauth2.AuthorizationCodeGrant(
+ 'identifier',
+ Uri.parse('https://example.com/authorization'),
+ Uri.parse('https://example.com/token'),
+ secret: 'secret',
+ basicAuth: false,
+ httpClient: client, onCredentialsRefreshed: (credentials) {
+ isCallbackInvoked = true;
+ });
+
+ grant.getAuthorizationUrl(redirectUrl);
+ client.expectRequest((request) {
+ return new Future.value(new http.Response(
+ jsonEncode({
+ 'access_token': 'access token',
+ 'token_type': 'bearer',
+ "expires_in": -3600,
+ "refresh_token": "refresh token",
+ }),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ var oauth2Client = await grant.handleAuthorizationCode('auth code');
+
+ client.expectRequest((request) {
+ return new Future.value(new http.Response(
+ jsonEncode(
+ {'access_token': 'new access token', 'token_type': 'bearer'}),
+ 200,
+ headers: {'content-type': 'application/json'}));
+ });
+
+ client.expectRequest((request) {
+ return new Future.value(new http.Response('good job', 200));
+ });
+
+ await oauth2Client.read(Uri.parse("http://example.com/resource"));
+
+ expect(isCallbackInvoked, equals(true));
+ });
+ });
}