extract method

  1. @override
Future<Result<T, Rejection>> extract(
  1. Request request
)
override

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(', '),
    ),
  );
}