extract method
Produces the value, or the rejection that stops the handler.
Implementation
@override
Future<Result<T, Rejection>> extract(Request request) async {
final refusals = <Rejection>[];
for (final extractor in extractors) {
switch (await extractor.extract(request)) {
case Ok(:final value):
return Ok(value);
case Err(:final error) when error.status >= 500:
return Err(error);
case Err(:final error):
refusals.add(error);
}
}
if (refusals.isEmpty) {
return const Err(Rejection.unauthorized('no credentials accepted'));
}
// Anything other than a 401 says a credential *was* presented and was not
// good enough. That is the more useful answer, so it is not buried under a
// challenge asking for one.
final refused = refusals.where((rejection) => rejection.status != 401);
if (refused.isNotEmpty) return Err(refused.last);
// Every scheme wanted a credential and none arrived, so offer them all.
final challenges = <String>{
for (final rejection in refusals)
if (rejection.challenge case final challenge?) challenge,
};
return Err(
Rejection.unauthorized(
'no credentials were supplied',
challenge: challenges.isEmpty ? 'Bearer' : challenges.join(', '),
),
);
}