@@ -6,8 +6,18 @@ import 'dart:convert';
66
77import 'package:http/http.dart' as http;
88
9+ /// An exception thrown when OAuth 2.0 discovery fails.
10+ class DiscoveryException implements Exception {
11+ final String message;
12+
13+ DiscoveryException (this .message);
14+
15+ @override
16+ String toString () => message;
17+ }
18+
919/// OAuth 2.0 Authorization Server Metadata (RFC 8414).
10- class OAuthServerMetadata {
20+ final class OAuthServerMetadata {
1121 /// The authorization server's issuer identifier.
1222 final String issuer;
1323
@@ -17,7 +27,8 @@ class OAuthServerMetadata {
1727 /// URL of the authorization server's token endpoint.
1828 final String tokenEndpoint;
1929
20- /// URL of the authorization server's OAuth 2.0 Dynamic Client Registration endpoint.
30+ /// URL of the authorization server's OAuth 2.0 Dynamic Client Registration
31+ /// endpoint.
2132 final String ? registrationEndpoint;
2233
2334 /// JSON array containing a list of the OAuth 2.0 scope values that this
@@ -40,8 +51,8 @@ class OAuthServerMetadata {
4051 /// by this authorization server.
4152 final List <String >? codeChallengeMethodsSupported;
4253
43- /// Boolean value specifying whether the authorization server supports multiple
44- /// issuers.
54+ /// Boolean value specifying whether the authorization server supports
55+ /// multiple issuers.
4556 final bool ? clientIdMetadataDocumentSupported;
4657
4758 const OAuthServerMetadata ({
@@ -80,11 +91,12 @@ class OAuthServerMetadata {
8091}
8192
8293/// OAuth 2.0 Protected Resource Metadata (RFC 9728).
83- class OAuthProtectedResourceMetadata {
94+ final class OAuthProtectedResourceMetadata {
8495 /// A URI that identifies the protected resource.
8596 final String resource;
8697
87- /// JSON array of authorization server identifiers that the protected resource trusts.
98+ /// JSON array of authorization server identifiers that the protected resource
99+ /// trusts.
88100 final List <String >? authorizationServers;
89101
90102 /// JSON array of the scope values that the protected resource supports.
@@ -134,7 +146,7 @@ Future<OAuthServerMetadata?> discoverAuthorizationServerMetadata(
134146 if (response.statusCode >= 400 && response.statusCode < 500 ) {
135147 continue ;
136148 }
137- throw StateError (
149+ throw DiscoveryException (
138150 'HTTP ${response .statusCode } loading authorization server '
139151 'metadata from $endpoint ' ,
140152 );
@@ -146,14 +158,14 @@ Future<OAuthServerMetadata?> discoverAuthorizationServerMetadata(
146158 final expectedIssuer = authorizationServerUrl.toString ();
147159 if (metadata.issuer.replaceAll (RegExp (r'/$' ), '' ) !=
148160 expectedIssuer.replaceAll (RegExp (r'/$' ), '' )) {
149- throw StateError (
161+ throw DiscoveryException (
150162 'Issuer spoofing detected: metadata issuer "${metadata .issuer }" '
151163 'does not match expected "$expectedIssuer ".' ,
152164 );
153165 }
154166 return metadata;
155167 } catch (e) {
156- if (e is StateError ) rethrow ;
168+ if (e is DiscoveryException ) rethrow ;
157169 continue ;
158170 }
159171 }
@@ -166,7 +178,8 @@ Future<OAuthServerMetadata?> discoverAuthorizationServerMetadata(
166178/// Discovers RFC 9728 OAuth 2.0 Protected Resource Metadata.
167179///
168180/// The returned [Future] completes with the metadata. It completes with a
169- /// [StateError] if the metadata endpoint is not found (HTTP 404).
181+ /// [DiscoveryException] if the metadata endpoint is not found (HTTP 404) or
182+ /// returns another invalid response.
170183Future <OAuthProtectedResourceMetadata > discoverProtectedResourceMetadata (
171184 Uri serverUrl, {
172185 Uri ? resourceMetadataUrl,
@@ -189,13 +202,13 @@ Future<OAuthProtectedResourceMetadata> discoverProtectedResourceMetadata(
189202
190203 final response = await client.get (url);
191204 if (response.statusCode == 404 ) {
192- throw StateError (
205+ throw DiscoveryException (
193206 'Resource server does not implement OAuth 2.0 Protected Resource '
194207 'Metadata.' ,
195208 );
196209 }
197210 if (response.statusCode < 200 || response.statusCode >= 300 ) {
198- throw StateError (
211+ throw DiscoveryException (
199212 'HTTP ${response .statusCode } loading protected resource metadata.' ,
200213 );
201214 }
@@ -206,7 +219,7 @@ Future<OAuthProtectedResourceMetadata> discoverProtectedResourceMetadata(
206219 final expectedResource = serverUrl.toString ();
207220 if (metadata.resource.replaceAll (RegExp (r'/$' ), '' ) !=
208221 expectedResource.replaceAll (RegExp (r'/$' ), '' )) {
209- throw StateError (
222+ throw DiscoveryException (
210223 'Resource spoofing detected: metadata resource "${metadata .resource }" '
211224 'does not match expected "$expectedResource ".' ,
212225 );
0 commit comments