Skip to content

Commit 62fb70d

Browse files
committed
📝 Updated public member documentation
1 parent c9f45d3 commit 62fb70d

File tree

8 files changed

+150
-57
lines changed

8 files changed

+150
-57
lines changed

lib/src/extensions/request.dart

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import 'package:chopper/chopper.dart';
22

3+
/// Helper extension to easily apply a authorization header to a request.
34
extension ChopperRequest on Request {
4-
Request addAuthorizationHeader(String token) {
5-
final newHeaders = Map<String, String>.from(headers);
6-
newHeaders['Authorization'] = 'Bearer $token';
7-
return copyWith(headers: newHeaders);
8-
}
5+
/// Adds a authorization header with a bearer [token] to the request.
6+
Request addAuthorizationHeader(String token) => applyHeader(
7+
this,
8+
'Authorization',
9+
'Bearer $token',
10+
);
911
}

lib/src/oauth_authenticator.dart

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,32 @@ import 'package:chopper/chopper.dart';
44
import 'package:oauth_chopper/oauth_chopper.dart';
55
import 'package:oauth_chopper/src/extensions/request.dart';
66

7+
/// Callback for error handling.
78
typedef OnErrorCallback = void Function(Object, StackTrace);
89

9-
/// OAuthAuthenticator provides a authenticator that handles OAuth authorizations.
10+
/// {@template authenticator}
11+
/// OAuthAuthenticator provides a authenticator that handles
12+
/// OAuth authorizations.
1013
/// When the provided credentials are invalid it tries to refresh them.
11-
/// Can throw a exceptions if no [onError] is passed. When [onError] is passed exception will be passed to [onError]
14+
/// Can throw a exceptions if no [onError] is passed. When [onError] is passed
15+
/// exception will be passed to [onError]
16+
/// {@endtemplate}
1217
class OAuthAuthenticator extends Authenticator {
18+
/// {@macro authenticator}
1319
OAuthAuthenticator(this.oauthChopper, this.onError);
1420

21+
/// Callback for error handling.
1522
final OnErrorCallback? onError;
23+
/// The [OAuthChopper] instance to get the token from and
24+
/// to refresh the token.
1625
final OAuthChopper oauthChopper;
1726

1827
@override
19-
FutureOr<Request?> authenticate(Request request, Response<dynamic> response,
20-
[Request? originalRequest]) async {
28+
FutureOr<Request?> authenticate(
29+
Request request,
30+
Response<dynamic> response, [
31+
Request? originalRequest,
32+
]) async {
2133
final token = await oauthChopper.token;
2234
if (response.statusCode == 401 && token != null) {
2335
try {

lib/src/oauth_chopper.dart

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:oauth_chopper/src/oauth_token.dart';
88
import 'package:oauth_chopper/src/storage/memory_storage.dart';
99
import 'package:oauth_chopper/src/storage/oauth_storage.dart';
1010

11+
/// {@template oauth_chopper}
1112
/// OAuthChopper client for configuring OAuth authentication with [Chopper].
1213
///
1314
/// For example:
@@ -18,7 +19,21 @@ import 'package:oauth_chopper/src/storage/oauth_storage.dart';
1819
/// secret: secret,
1920
/// );
2021
/// ```
22+
/// {@endtemplate}
2123
class OAuthChopper {
24+
/// {@macro oauth_chopper}
25+
OAuthChopper({
26+
required this.authorizationEndpoint,
27+
required this.identifier,
28+
required this.secret,
29+
this.endSessionEndpoint,
30+
31+
/// OAuth storage for storing credentials.
32+
/// By default it will use a in memory storage [MemoryStorage]. For persisting the credentials implement a custom [OAuthStorage].
33+
/// See [OAuthStorage] for more information.
34+
OAuthStorage? storage,
35+
}) : _storage = storage ?? MemoryStorage();
36+
2237
/// OAuth authorization endpoint.
2338
final Uri authorizationEndpoint;
2439

@@ -36,24 +51,10 @@ class OAuthChopper {
3651
/// See [OAuthStorage] for more information.
3752
final OAuthStorage _storage;
3853

39-
OAuthChopper({
40-
required this.authorizationEndpoint,
41-
required this.identifier,
42-
required this.secret,
43-
this.endSessionEndpoint,
44-
45-
/// OAuth storage for storing credentials.
46-
/// By default it will use a in memory storage [MemoryStorage]. For persisting the credentials implement a custom [OAuthStorage].
47-
/// See [OAuthStorage] for more information.
48-
OAuthStorage? storage,
49-
}) : _storage = storage ?? MemoryStorage();
50-
5154
/// Get stored [OAuthToken].
5255
Future<OAuthToken?> get token async {
5356
final credentialsJson = await _storage.fetchCredentials();
54-
return credentialsJson != null
55-
? OAuthToken.fromJson(credentialsJson)
56-
: null;
57+
return credentialsJson != null ? OAuthToken.fromJson(credentialsJson) : null;
5758
}
5859

5960
/// Provides an [OAuthAuthenticator] instance.
@@ -75,8 +76,7 @@ class OAuthChopper {
7576
if (credentialsJson == null) return null;
7677
final credentials = Credentials.fromJson(credentialsJson);
7778
try {
78-
final newCredentials =
79-
await credentials.refresh(identifier: identifier, secret: secret);
79+
final newCredentials = await credentials.refresh(identifier: identifier, secret: secret);
8080
await _storage.saveCredentials(newCredentials.toJson());
8181
return OAuthToken.fromCredentials(newCredentials);
8282
} on AuthorizationException {
@@ -92,8 +92,7 @@ class OAuthChopper {
9292
///
9393
/// Throws an exception if the grant fails.
9494
Future<OAuthToken> requestGrant(OAuthGrant grant) async {
95-
final credentials =
96-
await grant.handle(authorizationEndpoint, identifier, secret);
95+
final credentials = await grant.handle(authorizationEndpoint, identifier, secret);
9796

9897
await _storage.saveCredentials(credentials);
9998

lib/src/oauth_grant.dart

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,38 @@
11
import 'package:oauth2/oauth2.dart' as oauth;
22

3-
abstract class OAuthGrant {
3+
/// {@template oauth_grant}
4+
/// Interface for a OAuth grant.
5+
/// Grants are used to obtain credentials from an authorization server.
6+
/// {@endtemplate}
7+
abstract interface class OAuthGrant {
8+
/// {@macro oauth_grant}
49
const OAuthGrant();
510

6-
Future<String> handle(
7-
Uri authorizationEndpoint, String identifier, String secret);
11+
/// Obtains credentials from an authorization server.
12+
Future<String> handle(Uri authorizationEndpoint, String identifier, String secret);
813
}
914

15+
/// {@template resource_owner_password_grant}
1016
/// Obtains credentials using a [resource owner password grant](https://tools.ietf.org/html/rfc6749#section-1.3.3).
11-
class ResourceOwnerPasswordGrant extends OAuthGrant {
17+
///
18+
/// This grant uses the resource owner's [username] and [password] to obtain
19+
/// credentials.
20+
/// {@endtemplate}
21+
class ResourceOwnerPasswordGrant implements OAuthGrant {
22+
/// {@macro resource_owner_password_grant}
23+
const ResourceOwnerPasswordGrant({
24+
required this.username,
25+
required this.password,
26+
});
27+
28+
/// Username used for obtaining credentials.
1229
final String username;
13-
final String password;
1430

15-
const ResourceOwnerPasswordGrant(
16-
{required this.username, required this.password});
31+
/// Password used for obtaining credentials.
32+
final String password;
1733

1834
@override
19-
Future<String> handle(
20-
Uri authorizationEndpoint, String identifier, String secret) async {
35+
Future<String> handle(Uri authorizationEndpoint, String identifier, String secret) async {
2136
final client = await oauth.resourceOwnerPasswordGrant(
2237
authorizationEndpoint,
2338
username,
@@ -29,13 +44,15 @@ class ResourceOwnerPasswordGrant extends OAuthGrant {
2944
}
3045
}
3146

47+
/// {@template client_credentials_grant}
3248
/// Obtains credentials using a [client credentials grant](https://tools.ietf.org/html/rfc6749#section-1.3.4).
33-
class ClientCredentialsGrant extends OAuthGrant {
49+
/// {@endtemplate}
50+
class ClientCredentialsGrant implements OAuthGrant {
51+
/// {@macro client_credentials_grant}
3452
const ClientCredentialsGrant();
3553

3654
@override
37-
Future<String> handle(
38-
Uri authorizationEndpoint, String identifier, String secret) async {
55+
Future<String> handle(Uri authorizationEndpoint, String identifier, String secret) async {
3956
final client = await oauth.clientCredentialsGrant(
4057
authorizationEndpoint,
4158
identifier,
@@ -45,8 +62,11 @@ class ClientCredentialsGrant extends OAuthGrant {
4562
}
4663
}
4764

65+
/// {@template authorization_code_grant}
4866
/// Obtains credentials using a [authorization code grant](https://tools.ietf.org/html/rfc6749#section-1.3.1).
49-
class AuthorizationCodeGrant extends OAuthGrant {
67+
/// {@endtemplate}
68+
class AuthorizationCodeGrant implements OAuthGrant {
69+
/// {@macro authorization_code_grant}
5070
const AuthorizationCodeGrant({
5171
required this.tokenEndpoint,
5272
required this.scopes,
@@ -55,26 +75,48 @@ class AuthorizationCodeGrant extends OAuthGrant {
5575
required this.listen,
5676
});
5777

78+
/// A URL provided by the authorization server that this library uses to
79+
/// obtain long-lasting credentials.
80+
///
81+
/// This will usually be listed in the authorization server's OAuth2 API
82+
/// documentation.
5883
final Uri tokenEndpoint;
84+
85+
/// The redirect URL where the resource owner will redirect to.
5986
final Uri redirectUrl;
87+
88+
/// The specific permissions being requested from the authorization server may
89+
/// be specified via [scopes].
6090
final List<String> scopes;
91+
/// Callback used for redirect the authorizationUrl given by the authorization
92+
/// server.
6193
final Future<void> Function(Uri authorizationUri) redirect;
94+
/// Callback used for listening for the redirectUrl.
6295
final Future<Uri> Function(Uri redirectUri) listen;
6396

6497
@override
6598
Future<String> handle(
66-
Uri authorizationEndpoint, String identifier, String secret) async {
99+
Uri authorizationEndpoint,
100+
String identifier,
101+
String secret,
102+
) async {
67103
final grant = oauth.AuthorizationCodeGrant(
68104
identifier,
69105
authorizationEndpoint,
70106
tokenEndpoint,
71107
);
72-
var authorizationUrl =
73-
grant.getAuthorizationUrl(redirectUrl, scopes: scopes);
108+
109+
final authorizationUrl = grant.getAuthorizationUrl(
110+
redirectUrl,
111+
scopes: scopes,
112+
);
113+
74114
await redirect(authorizationUrl);
75-
var responseUrl = await listen(redirectUrl);
76-
oauth.Client client =
77-
await grant.handleAuthorizationResponse(responseUrl.queryParameters);
115+
final responseUrl = await listen(redirectUrl);
116+
117+
final oauth.Client client = await grant.handleAuthorizationResponse(
118+
responseUrl.queryParameters,
119+
);
78120

79121
return client.credentials.toJson();
80122
}

lib/src/oauth_interceptor.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ import 'package:chopper/chopper.dart';
44
import 'package:oauth_chopper/oauth_chopper.dart';
55
import 'package:oauth_chopper/src/extensions/request.dart';
66

7+
/// {@template oauth_interceptor}
78
/// OAuthInterceptor is responsible for adding 'Authorization' header to requests.
89
/// The header is only added if there is a token available. When no token is available no header is added.
910
/// Its added as a Bearer token.
11+
/// {@endtemplate}
1012
class OAuthInterceptor implements RequestInterceptor {
13+
/// {@macro oauth_interceptor}
1114
OAuthInterceptor(this.oauthChopper);
1215

16+
/// The [OAuthChopper] instance to get the token from.
1317
final OAuthChopper oauthChopper;
1418

1519
@override

lib/src/oauth_token.dart

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,63 @@
11
import 'package:oauth2/oauth2.dart';
22

3+
/// {@template oauth_token}
4+
/// A wrapper around [Credentials] to provide a more convenient API.
5+
/// {@endtemplate}
36
class OAuthToken {
4-
final String accessToken;
5-
final String? refreshToken;
6-
final DateTime? expiration;
7-
final String? idToken;
8-
9-
bool get isExpired =>
10-
expiration != null && DateTime.now().isAfter(expiration!);
11-
7+
/// {@macro oauth_token}
128
const OAuthToken._(
139
this.accessToken,
1410
this.refreshToken,
1511
this.expiration,
1612
this.idToken,
1713
);
1814

15+
/// Creates a new instance of [OAuthToken] from a JSON string.
16+
/// {@macro oauth_token}
1917
factory OAuthToken.fromJson(String json) {
2018
final credentials = Credentials.fromJson(json);
2119
return OAuthToken.fromCredentials(credentials);
2220
}
2321

22+
/// Creates a new instance of [OAuthToken] from [Credentials].
23+
/// {@macro oauth_token}
2424
factory OAuthToken.fromCredentials(Credentials credentials) => OAuthToken._(
2525
credentials.accessToken,
2626
credentials.refreshToken,
2727
credentials.expiration,
2828
credentials.idToken,
2929
);
30+
31+
/// The token that is sent to the resource server to prove the authorization
32+
/// of a client.
33+
final String accessToken;
34+
35+
/// The token that is sent to the authorization server to refresh the
36+
/// credentials.
37+
///
38+
/// This may be `null`, indicating that the credentials can't be refreshed.
39+
final String? refreshToken;
40+
41+
/// The date at which these credentials will expire.
42+
///
43+
/// This is likely to be a few seconds earlier than the server's idea of the
44+
/// expiration date.
45+
final DateTime? expiration;
46+
47+
/// The token that is received from the authorization server to enable
48+
/// End-Users to be Authenticated, contains Claims, represented as a
49+
/// JSON Web Token (JWT).
50+
///
51+
/// This may be `null`, indicating that the 'openid' scope was not
52+
/// requested (or not supported).
53+
///
54+
/// [spec]: https://openid.net/specs/openid-connect-core-1_0.html#IDToken
55+
final String? idToken;
56+
57+
/// Whether the token is expired.
58+
bool get isExpired =>
59+
expiration != null &&
60+
DateTime.now().isAfter(
61+
expiration!,
62+
);
3063
}

lib/src/storage/oauth_storage.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:async';
22

3-
abstract class OAuthStorage {
3+
/// Interface for storage of OAuth credentials.
4+
abstract interface class OAuthStorage {
45
const OAuthStorage();
56

67
/// Fetch stored credentials.

test/oauth_interceptor_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void main() {
5959
// arrange
6060
when(() => mockOAuthChopper.token).thenAnswer((_) async => null);
6161
final interceptor = OAuthInterceptor(mockOAuthChopper);
62-
final expected = {};
62+
final expected = <String, String>{};
6363

6464
// act
6565
final result = await interceptor.onRequest(testRequest);

0 commit comments

Comments
 (0)