Skip to content

feat: add support for OAuth 2.0 discovery, registration, resource indicators, and custom auth#2338

Open
pavelgj wants to merge 23 commits into
dart-lang:mainfrom
pavelgj:pj/discovery
Open

feat: add support for OAuth 2.0 discovery, registration, resource indicators, and custom auth#2338
pavelgj wants to merge 23 commits into
dart-lang:mainfrom
pavelgj:pj/discovery

Conversation

@pavelgj
Copy link
Copy Markdown

@pavelgj pavelgj commented Mar 3, 2026

This PR implements several advanced OAuth 2.0 and OpenID Connect features into package:oauth2 to support more complex enterprise and OIDC flows without breaking existing logic.

Features Added

  • Server Discovery (RFC 8414 & RFC 9728):
    • Added discoverAuthorizationServerMetadata and discoverProtectedResourceMetadata functions in the new lib/src/discovery.dart file.
    • Fetches and parses metadata from /.well-known/oauth-authorization-server and OpenID Connect discovery endpoints, complete with standard robust fallbacks.
  • Dynamic Client Registration (RFC 7591):
    • Added registerClient in the new lib/src/registration.dart file for dynamic client provisioning scenarios.
  • Resource Indicators (RFC 8707):
    • Added Iterable<Uri>? resources optional parameters to AuthorizationCodeGrant.getAuthorizationUrl, ClientCredentialsGrant.clientCredentialsGrant, and Credentials.refresh().
  • Custom Client Authenticators:
    • Introduced ClientAuthenticator typedef for injecting custom client assertions (e.g., JWTs for RFC 7523) during token exchange.
    • Optionally replaces basic auth headers within AuthorizationCodeGrant, ClientCredentialsGrant, and Client.refreshCredentials(), which is propagated during token refresh.

Testing

  • Added comprehensive integration tests in test/discovery_test.dart and test/registration_test.dart simulating server endpoints using ExpectClient.
  • All existing tests for various grant flows have been verified to pass alongside the new features.
  • I’ve reviewed the contributor guide and applied the relevant portions to this PR.

@pavelgj pavelgj requested a review from a team as a code owner March 3, 2026 17:05
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces substantial new features to package:oauth2, including support for OAuth 2.0 server discovery, dynamic client registration, resource indicators, and custom client authenticators. However, the implementation has critical security flaws. The discovery mechanism lacks mandatory issuer validation required by RFC 8414, which could allow for issuer spoofing. Additionally, the implementation of resource indicators (RFC 8707) is non-compliant as it incorrectly joins multiple resources into a single parameter, potentially leading to incorrect authorization behavior. Addressing these security issues is crucial. Furthermore, there is a minor suggestion to enhance code readability and null-safety practices.

Comment thread pkgs/oauth2/lib/src/discovery.dart Outdated
Comment thread pkgs/oauth2/lib/src/authorization_code_grant.dart Outdated
Comment thread pkgs/oauth2/lib/src/client_credentials_grant.dart Outdated
Comment thread pkgs/oauth2/lib/src/credentials.dart Outdated
Comment thread pkgs/oauth2/lib/src/registration.dart Outdated
@pavelgj
Copy link
Copy Markdown
Author

pavelgj commented Mar 3, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new features to package:oauth2, including support for OAuth 2.0 server discovery, dynamic client registration, resource indicators, and custom client authenticators. While the implementation is generally robust, a critical security issue was identified in the discovery of protected resource metadata. Specifically, the library fails to verify the resource field in the metadata against the resource identifier used for discovery, which is a requirement of RFC 9728 to prevent metadata spoofing. Additionally, my review noted a couple of instances of code duplication in the new logic that could be refactored to improve maintainability.

Comment thread pkgs/oauth2/lib/src/discovery.dart
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 3, 2026

Package publishing

Package Version Status Publish tag (post-merge)
package:bazel_worker 1.1.5 already published at pub.dev
package:benchmark_harness 2.4.0 already published at pub.dev
package:boolean_selector 2.1.2 already published at pub.dev
package:browser_launcher 1.2.0-wip WIP (no publish necessary)
package:cli_config 0.2.1-wip WIP (no publish necessary)
package:cli_util 0.5.0-wip WIP (no publish necessary)
package:clock 1.1.3-wip WIP (no publish necessary)
package:code_builder 4.11.1 already published at pub.dev
package:coverage 1.15.0 already published at pub.dev
package:csslib 1.0.2 already published at pub.dev
package:extension_discovery 2.1.0 already published at pub.dev
package:file 7.0.2-wip WIP (no publish necessary)
package:file_testing 3.1.0-wip WIP (no publish necessary)
package:glob 2.1.3 already published at pub.dev
package:graphs 2.4.0-wip WIP (no publish necessary)
package:html 0.15.7-wip WIP (no publish necessary)
package:io 1.1.0-wip WIP (no publish necessary)
package:json_rpc_2 4.1.0 already published at pub.dev
package:markdown 7.3.1 ready to publish markdown-v7.3.1
package:mime 2.1.0-wip WIP (no publish necessary)
package:oauth2 2.1.0 ready to publish oauth2-v2.1.0
package:package_config 2.3.0-wip WIP (no publish necessary)
package:pool 1.5.2 already published at pub.dev
package:process 5.0.5 (error) pubspec version (5.0.5) and changelog (5.0.6-wip) don't agree
package:pub_semver 2.2.0 already published at pub.dev
package:pubspec_parse 1.6.0-wip WIP (no publish necessary)
package:source_map_stack_trace 2.1.3-wip WIP (no publish necessary)
package:source_maps 0.10.14-wip WIP (no publish necessary)
package:source_span 1.10.2 already published at pub.dev
package:sse 4.2.0-wip (error) pubspec version (4.2.0-wip) and changelog (4.2.0) don't agree
package:stack_trace 1.12.2-wip (error) pubspec version (1.12.2-wip) and changelog (1.12.2-dev) don't agree
package:stream_channel 2.1.4 already published at pub.dev
package:stream_transform 2.1.2-wip WIP (no publish necessary)
package:string_scanner 1.4.2-wip WIP (no publish necessary)
package:term_glyph 1.2.3-wip WIP (no publish necessary)
package:test_reflective_loader 0.6.0 ready to publish test_reflective_loader-v0.6.0
package:timing 1.0.2 already published at pub.dev
package:unified_analytics 8.0.12-wip WIP (no publish necessary)
package:watcher 1.2.2-wip WIP (no publish necessary)
package:yaml 3.1.3 already published at pub.dev
package:yaml_edit 2.2.4 already published at pub.dev

Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 3, 2026

PR Health

Coverage ⚠️
File Coverage
pkgs/oauth2/lib/oauth2.dart 💔 Not covered
pkgs/oauth2/lib/src/authorization_code_grant.dart 💔 Not covered
pkgs/oauth2/lib/src/client.dart 💔 Not covered
pkgs/oauth2/lib/src/client_authenticator.dart 💔 Not covered
pkgs/oauth2/lib/src/client_credentials_grant.dart 💔 Not covered
pkgs/oauth2/lib/src/credentials.dart 💔 Not covered
pkgs/oauth2/lib/src/discovery.dart 💔 Not covered
pkgs/oauth2/lib/src/registration.dart 💔 Not covered
pkgs/oauth2/lib/src/utils.dart 💔 Not covered

This check for test coverage is informational (issues shown here will not fail the PR).

This check can be disabled by tagging the PR with skip-coverage-check.

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?
oauth2 Non-Breaking 2.0.5 2.1.0 2.1.0 ✔️

This check can be disabled by tagging the PR with skip-breaking-check.

Unused Dependencies ✔️
Package Status
oauth2 ✔️ All dependencies utilized correctly.

For details on how to fix these, see dependency_validator.

This check can be disabled by tagging the PR with skip-unused-dependencies-check.

Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

This check can be disabled by tagging the PR with skip-changelog-check.

License Headers ⚠️
""
Files
pkgs/oauth2/lib/oauth2.dart
pkgs/oauth2/lib/src/authorization_code_grant.dart
pkgs/oauth2/lib/src/client.dart
pkgs/oauth2/lib/src/client_authenticator.dart
pkgs/oauth2/lib/src/client_credentials_grant.dart
pkgs/oauth2/lib/src/credentials.dart
pkgs/oauth2/lib/src/discovery.dart
pkgs/oauth2/lib/src/registration.dart
pkgs/oauth2/lib/src/utils.dart
pkgs/oauth2/test/discovery_test.dart
pkgs/oauth2/test/registration_test.dart

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/bazel_worker/benchmark/benchmark.dart
pkgs/bazel_worker/e2e_test/bin/async_worker.dart
pkgs/bazel_worker/e2e_test/bin/async_worker_in_isolate.dart
pkgs/bazel_worker/e2e_test/bin/sync_worker.dart
pkgs/bazel_worker/e2e_test/lib/async_worker.dart
pkgs/bazel_worker/e2e_test/lib/forwards_to_isolate_async_worker.dart
pkgs/bazel_worker/e2e_test/lib/sync_worker.dart
pkgs/bazel_worker/e2e_test/test/e2e_test.dart
pkgs/bazel_worker/example/client.dart
pkgs/bazel_worker/example/worker.dart
pkgs/bazel_worker/lib/bazel_worker.dart
pkgs/bazel_worker/lib/driver.dart
pkgs/bazel_worker/lib/src/async_message_grouper.dart
pkgs/bazel_worker/lib/src/constants.dart
pkgs/bazel_worker/lib/src/driver/driver.dart
pkgs/bazel_worker/lib/src/driver/driver_connection.dart
pkgs/bazel_worker/lib/src/message_grouper.dart
pkgs/bazel_worker/lib/src/message_grouper_state.dart
pkgs/bazel_worker/lib/src/sync_message_grouper.dart
pkgs/bazel_worker/lib/src/utils.dart
pkgs/bazel_worker/lib/src/worker/async_worker_loop.dart
pkgs/bazel_worker/lib/src/worker/sync_worker_loop.dart
pkgs/bazel_worker/lib/src/worker/worker_connection.dart
pkgs/bazel_worker/lib/src/worker/worker_loop.dart
pkgs/bazel_worker/lib/testing.dart
pkgs/bazel_worker/test/driver_connection_test.dart
pkgs/bazel_worker/test/driver_test.dart
pkgs/bazel_worker/test/message_grouper_test.dart
pkgs/bazel_worker/test/test_all.dart
pkgs/bazel_worker/test/worker_loop_test.dart
pkgs/benchmark_harness/bin/bench.dart
pkgs/benchmark_harness/example/template.dart
pkgs/benchmark_harness/integration_test/perf_benchmark_test.dart
pkgs/benchmark_harness/lib/benchmark_harness.dart
pkgs/benchmark_harness/lib/perf_benchmark_harness.dart
pkgs/benchmark_harness/lib/src/async_benchmark_base.dart
pkgs/benchmark_harness/lib/src/bench_command/bench_options.dart
pkgs/benchmark_harness/lib/src/bench_command/compile_and_run.dart
pkgs/benchmark_harness/lib/src/benchmark_base.dart
pkgs/benchmark_harness/lib/src/measurement.dart
pkgs/benchmark_harness/lib/src/perf_benchmark_base.dart
pkgs/benchmark_harness/lib/src/perf_benchmark_base_stub.dart
pkgs/benchmark_harness/lib/src/score_emitter.dart
pkgs/benchmark_harness/test/bench_command_test.dart
pkgs/benchmark_harness/test/benchmark_harness_test.dart
pkgs/benchmark_harness/test/result_emitter_test.dart
pkgs/boolean_selector/example/example.dart
pkgs/boolean_selector/lib/boolean_selector.dart
pkgs/boolean_selector/lib/src/all.dart
pkgs/boolean_selector/lib/src/ast.dart
pkgs/boolean_selector/lib/src/evaluator.dart
pkgs/boolean_selector/lib/src/impl.dart
pkgs/boolean_selector/lib/src/intersection_selector.dart
pkgs/boolean_selector/lib/src/none.dart
pkgs/boolean_selector/lib/src/parser.dart
pkgs/boolean_selector/lib/src/scanner.dart
pkgs/boolean_selector/lib/src/token.dart
pkgs/boolean_selector/lib/src/union_selector.dart
pkgs/boolean_selector/lib/src/validator.dart
pkgs/boolean_selector/lib/src/visitor.dart
pkgs/boolean_selector/test/equality_test.dart
pkgs/boolean_selector/test/evaluate_test.dart
pkgs/boolean_selector/test/parser_test.dart
pkgs/boolean_selector/test/scanner_test.dart
pkgs/boolean_selector/test/to_string_test.dart
pkgs/boolean_selector/test/validate_test.dart
pkgs/boolean_selector/test/variables_test.dart
pkgs/browser_launcher/example/main.dart
pkgs/browser_launcher/lib/browser_launcher.dart
pkgs/browser_launcher/lib/src/chrome.dart
pkgs/browser_launcher/test/chrome_test.dart
pkgs/cli_config/example/bin/cli_config_example.dart
pkgs/cli_config/lib/cli_config.dart
pkgs/cli_config/lib/src/cli_parser.dart
pkgs/cli_config/lib/src/cli_source.dart
pkgs/cli_config/lib/src/config.dart
pkgs/cli_config/lib/src/environment_parser.dart
pkgs/cli_config/lib/src/environment_source.dart
pkgs/cli_config/lib/src/file_parser.dart
pkgs/cli_config/lib/src/file_source.dart
pkgs/cli_config/lib/src/source.dart
pkgs/cli_config/test/cli_config_example_test.dart
pkgs/cli_config/test/cli_config_test.dart
pkgs/cli_config/test/cli_config_windows_test.dart
pkgs/cli_config/test/helpers.dart
pkgs/cli_util/example/main.dart
pkgs/cli_util/lib/cli_logging.dart
pkgs/cli_util/lib/cli_util.dart
pkgs/cli_util/lib/src/base_directories.dart
pkgs/cli_util/test/base_directories_test.dart
pkgs/cli_util/test/cli_util_test.dart
pkgs/clock/lib/clock.dart
pkgs/clock/lib/src/clock.dart
pkgs/clock/lib/src/default.dart
pkgs/clock/lib/src/stopwatch.dart
pkgs/clock/lib/src/utils.dart
pkgs/clock/test/clock_test.dart
pkgs/clock/test/default_test.dart
pkgs/clock/test/stopwatch_test.dart
pkgs/clock/test/utils.dart
pkgs/code_builder/example/example.dart
pkgs/code_builder/lib/code_builder.dart
pkgs/code_builder/lib/src/allocator.dart
pkgs/code_builder/lib/src/base.dart
pkgs/code_builder/lib/src/emitter.dart
pkgs/code_builder/lib/src/matchers.dart
pkgs/code_builder/lib/src/mixins/annotations.dart
pkgs/code_builder/lib/src/mixins/dartdoc.dart
pkgs/code_builder/lib/src/mixins/generics.dart
pkgs/code_builder/lib/src/specs/class.dart
pkgs/code_builder/lib/src/specs/code.dart
pkgs/code_builder/lib/src/specs/constructor.dart
pkgs/code_builder/lib/src/specs/directive.dart
pkgs/code_builder/lib/src/specs/enum.dart
pkgs/code_builder/lib/src/specs/expression.dart
pkgs/code_builder/lib/src/specs/expression/binary.dart
pkgs/code_builder/lib/src/specs/expression/closure.dart
pkgs/code_builder/lib/src/specs/expression/code.dart
pkgs/code_builder/lib/src/specs/expression/invoke.dart
pkgs/code_builder/lib/src/specs/expression/literal.dart
pkgs/code_builder/lib/src/specs/expression/parenthesized.dart
pkgs/code_builder/lib/src/specs/extension.dart
pkgs/code_builder/lib/src/specs/extension_type.dart
pkgs/code_builder/lib/src/specs/field.dart
pkgs/code_builder/lib/src/specs/library.dart
pkgs/code_builder/lib/src/specs/method.dart
pkgs/code_builder/lib/src/specs/mixin.dart
pkgs/code_builder/lib/src/specs/reference.dart
pkgs/code_builder/lib/src/specs/type_function.dart
pkgs/code_builder/lib/src/specs/type_record.dart
pkgs/code_builder/lib/src/specs/type_reference.dart
pkgs/code_builder/lib/src/specs/typedef.dart
pkgs/code_builder/lib/src/visitors.dart
pkgs/code_builder/test/allocator_test.dart
pkgs/code_builder/test/common.dart
pkgs/code_builder/test/const_test.dart
pkgs/code_builder/test/directive_test.dart
pkgs/code_builder/test/e2e/injection_test.dart
pkgs/code_builder/test/matcher_test.dart
pkgs/code_builder/test/specs/class_test.dart
pkgs/code_builder/test/specs/code/expression_test.dart
pkgs/code_builder/test/specs/code/statement_test.dart
pkgs/code_builder/test/specs/enum_test.dart
pkgs/code_builder/test/specs/extension_test.dart
pkgs/code_builder/test/specs/extension_type_test.dart
pkgs/code_builder/test/specs/field_test.dart
pkgs/code_builder/test/specs/library_test.dart
pkgs/code_builder/test/specs/method_test.dart
pkgs/code_builder/test/specs/mixin_test.dart
pkgs/code_builder/test/specs/record_type_test.dart
pkgs/code_builder/test/specs/type_reference_test.dart
pkgs/coverage/benchmark/many_isolates.dart
pkgs/coverage/bin/collect_coverage.dart
pkgs/coverage/bin/format_coverage.dart
pkgs/coverage/bin/run_and_collect.dart
pkgs/coverage/bin/test_with_coverage.dart
pkgs/coverage/lib/coverage.dart
pkgs/coverage/lib/src/chrome.dart
pkgs/coverage/lib/src/collect.dart
pkgs/coverage/lib/src/coverage_options.dart
pkgs/coverage/lib/src/coverage_percentage.dart
pkgs/coverage/lib/src/formatter.dart
pkgs/coverage/lib/src/hitmap.dart
pkgs/coverage/lib/src/isolate_paused_listener.dart
pkgs/coverage/lib/src/resolver.dart
pkgs/coverage/lib/src/run_and_collect.dart
pkgs/coverage/lib/src/util.dart
pkgs/coverage/test/chrome_test.dart
pkgs/coverage/test/collect_coverage_api_test.dart
pkgs/coverage/test/collect_coverage_config_test.dart
pkgs/coverage/test/collect_coverage_mock_test.dart
pkgs/coverage/test/collect_coverage_test.dart
pkgs/coverage/test/config_file_locator_test.dart
pkgs/coverage/test/coverage_percentage_test.dart
pkgs/coverage/test/filter_ignored_test.dart
pkgs/coverage/test/format_coverage_test.dart
pkgs/coverage/test/function_coverage_test.dart
pkgs/coverage/test/isolate_paused_listener_test.dart
pkgs/coverage/test/lcov_test.dart
pkgs/coverage/test/resolver_test.dart
pkgs/coverage/test/run_and_collect_test.dart
pkgs/coverage/test/test_files/function_coverage_app.dart
pkgs/coverage/test/test_files/test_app.dart
pkgs/coverage/test/test_files/test_app_isolate.dart
pkgs/coverage/test/test_files/test_library.dart
pkgs/coverage/test/test_files/test_library_part.dart
pkgs/coverage/test/test_util.dart
pkgs/coverage/test/test_with_coverage_package/lib/validate_lib.dart
pkgs/coverage/test/test_with_coverage_package/test/evaluate_test.dart
pkgs/coverage/test/test_with_coverage_package/test/product_test.dart
pkgs/coverage/test/test_with_coverage_package/test/sum_test.dart
pkgs/coverage/test/test_with_coverage_test.dart
pkgs/coverage/test/util_test.dart
pkgs/csslib/example/main.dart
pkgs/csslib/lib/src/analyzer.dart
pkgs/csslib/lib/src/css_printer.dart
pkgs/csslib/lib/src/messages.dart
pkgs/csslib/lib/src/polyfill.dart
pkgs/csslib/lib/src/preprocessor_options.dart
pkgs/csslib/lib/src/property.dart
pkgs/csslib/lib/src/token.dart
pkgs/csslib/lib/src/token_kind.dart
pkgs/csslib/lib/src/tokenizer.dart
pkgs/csslib/lib/src/tree.dart
pkgs/csslib/lib/src/tree_base.dart
pkgs/csslib/lib/src/tree_printer.dart
pkgs/csslib/lib/src/validate.dart
pkgs/csslib/lib/visitor.dart
pkgs/csslib/test/big_1_test.dart
pkgs/csslib/test/color_test.dart
pkgs/csslib/test/debug_test.dart
pkgs/csslib/test/declaration_test.dart
pkgs/csslib/test/error_test.dart
pkgs/csslib/test/escape_codes_test.dart
pkgs/csslib/test/extend_test.dart
pkgs/csslib/test/keyframes_test.dart
pkgs/csslib/test/mixin_test.dart
pkgs/csslib/test/nested_test.dart
pkgs/csslib/test/repros_test.dart
pkgs/csslib/test/selector_test.dart
pkgs/csslib/test/testing.dart
pkgs/csslib/test/third_party_samples_test.dart
pkgs/csslib/test/var_test.dart
pkgs/csslib/test/visitor_test.dart
pkgs/extension_discovery/example/hello_world/lib/hello_world.dart
pkgs/extension_discovery/example/hello_world_app/bin/hello.dart
pkgs/extension_discovery/lib/extension_discovery.dart
pkgs/extension_discovery/lib/src/expect_json.dart
pkgs/extension_discovery/lib/src/io.dart
pkgs/extension_discovery/lib/src/package_config.dart
pkgs/extension_discovery/lib/src/registry.dart
pkgs/extension_discovery/lib/src/yaml_config_format.dart
pkgs/extension_discovery/test/find_extensions_test.dart
pkgs/extension_discovery/test/integration_test.dart
pkgs/extension_discovery/test/package_config_test.dart
pkgs/extension_discovery/test/test_descriptor.dart
pkgs/extension_discovery/test/yaml_config_format_test.dart
pkgs/file/example/main.dart
pkgs/file/lib/chroot.dart
pkgs/file/lib/file.dart
pkgs/file/lib/local.dart
pkgs/file/lib/memory.dart
pkgs/file/lib/src/backends/chroot.dart
pkgs/file/lib/src/backends/chroot/chroot_directory.dart
pkgs/file/lib/src/backends/chroot/chroot_file.dart
pkgs/file/lib/src/backends/chroot/chroot_file_system.dart
pkgs/file/lib/src/backends/chroot/chroot_file_system_entity.dart
pkgs/file/lib/src/backends/chroot/chroot_link.dart
pkgs/file/lib/src/backends/chroot/chroot_random_access_file.dart
pkgs/file/lib/src/backends/local.dart
pkgs/file/lib/src/backends/local/local_directory.dart
pkgs/file/lib/src/backends/local/local_file.dart
pkgs/file/lib/src/backends/local/local_file_system.dart
pkgs/file/lib/src/backends/local/local_file_system_entity.dart
pkgs/file/lib/src/backends/local/local_link.dart
pkgs/file/lib/src/backends/memory.dart
pkgs/file/lib/src/backends/memory/clock.dart
pkgs/file/lib/src/backends/memory/common.dart
pkgs/file/lib/src/backends/memory/memory_directory.dart
pkgs/file/lib/src/backends/memory/memory_file.dart
pkgs/file/lib/src/backends/memory/memory_file_stat.dart
pkgs/file/lib/src/backends/memory/memory_file_system.dart
pkgs/file/lib/src/backends/memory/memory_file_system_entity.dart
pkgs/file/lib/src/backends/memory/memory_link.dart
pkgs/file/lib/src/backends/memory/memory_random_access_file.dart
pkgs/file/lib/src/backends/memory/node.dart
pkgs/file/lib/src/backends/memory/operations.dart
pkgs/file/lib/src/backends/memory/style.dart
pkgs/file/lib/src/backends/memory/utils.dart
pkgs/file/lib/src/common.dart
pkgs/file/lib/src/forwarding.dart
pkgs/file/lib/src/forwarding/forwarding_directory.dart
pkgs/file/lib/src/forwarding/forwarding_file.dart
pkgs/file/lib/src/forwarding/forwarding_file_system.dart
pkgs/file/lib/src/forwarding/forwarding_file_system_entity.dart
pkgs/file/lib/src/forwarding/forwarding_link.dart
pkgs/file/lib/src/forwarding/forwarding_random_access_file.dart
pkgs/file/lib/src/interface.dart
pkgs/file/lib/src/interface/directory.dart
pkgs/file/lib/src/interface/error_codes.dart
pkgs/file/lib/src/interface/error_codes_dart_io.dart
pkgs/file/lib/src/interface/error_codes_internal.dart
pkgs/file/lib/src/interface/file.dart
pkgs/file/lib/src/interface/file_system.dart
pkgs/file/lib/src/interface/file_system_entity.dart
pkgs/file/lib/src/interface/link.dart
pkgs/file/lib/src/io.dart
pkgs/file/test/chroot_test.dart
pkgs/file/test/common_tests.dart
pkgs/file/test/local_test.dart
pkgs/file/test/memory_operations_test.dart
pkgs/file/test/memory_test.dart
pkgs/file/test/utils.dart
pkgs/file/test/utils_test.dart
pkgs/file_testing/lib/file_testing.dart
pkgs/file_testing/lib/src/testing/core_matchers.dart
pkgs/file_testing/lib/src/testing/internal.dart
pkgs/glob/lib/glob.dart
pkgs/glob/lib/list_local_fs.dart
pkgs/glob/lib/src/ast.dart
pkgs/glob/lib/src/list_tree.dart
pkgs/glob/lib/src/parser.dart
pkgs/glob/lib/src/stream_pool.dart
pkgs/glob/lib/src/utils.dart
pkgs/glob/test/glob_test.dart
pkgs/glob/test/list_test.dart
pkgs/glob/test/match_test.dart
pkgs/glob/test/parse_test.dart
pkgs/graphs/benchmark/connected_components_benchmark.dart
pkgs/graphs/benchmark/shortest_path_benchmark.dart
pkgs/graphs/benchmark/shortest_path_worst_case_benchmark.dart
pkgs/graphs/example/crawl_async_example.dart
pkgs/graphs/example/example.dart
pkgs/graphs/lib/graphs.dart
pkgs/graphs/lib/src/crawl_async.dart
pkgs/graphs/lib/src/cycle_exception.dart
pkgs/graphs/lib/src/shortest_path.dart
pkgs/graphs/lib/src/strongly_connected_components.dart
pkgs/graphs/lib/src/topological_sort.dart
pkgs/graphs/lib/src/transitive_closure.dart
pkgs/graphs/test/crawl_async_test.dart
pkgs/graphs/test/shortest_path_test.dart
pkgs/graphs/test/strongly_connected_components_test.dart
pkgs/graphs/test/topological_sort_test.dart
pkgs/graphs/test/transitive_closure_test.dart
pkgs/graphs/test/utils/graph.dart
pkgs/graphs/test/utils/utils.dart
pkgs/html/example/main.dart
pkgs/html/lib/dom.dart
pkgs/html/lib/dom_parsing.dart
pkgs/html/lib/html_escape.dart
pkgs/html/lib/parser.dart
pkgs/html/lib/src/constants.dart
pkgs/html/lib/src/css_class_set.dart
pkgs/html/lib/src/encoding_parser.dart
pkgs/html/lib/src/html_input_stream.dart
pkgs/html/lib/src/list_proxy.dart
pkgs/html/lib/src/query_selector.dart
pkgs/html/lib/src/token.dart
pkgs/html/lib/src/tokenizer.dart
pkgs/html/lib/src/treebuilder.dart
pkgs/html/lib/src/utils.dart
pkgs/html/test/dom_test.dart
pkgs/html/test/parser_feature_test.dart
pkgs/html/test/parser_test.dart
pkgs/html/test/query_selector_test.dart
pkgs/html/test/selectors/level1_baseline_test.dart
pkgs/html/test/selectors/level1_lib.dart
pkgs/html/test/support.dart
pkgs/html/test/tokenizer_test.dart
pkgs/html/test/trie_test.dart
pkgs/html/tool/generate_trie.dart
pkgs/io/example/example.dart
pkgs/io/example/spawn_process_example.dart
pkgs/io/lib/ansi.dart
pkgs/io/lib/io.dart
pkgs/io/lib/src/ansi_code.dart
pkgs/io/lib/src/copy_path.dart
pkgs/io/lib/src/exit_code.dart
pkgs/io/lib/src/permissions.dart
pkgs/io/lib/src/process_manager.dart
pkgs/io/lib/src/shared_stdin.dart
pkgs/io/test/_files/stderr_hello.dart
pkgs/io/test/_files/stdin_echo.dart
pkgs/io/test/_files/stdout_hello.dart
pkgs/io/test/ansi_code_test.dart
pkgs/io/test/copy_path_test.dart
pkgs/io/test/permissions_test.dart
pkgs/io/test/process_manager_test.dart
pkgs/io/test/shared_stdin_test.dart
pkgs/json_rpc_2/example/client.dart
pkgs/json_rpc_2/example/main.dart
pkgs/json_rpc_2/lib/error_code.dart
pkgs/json_rpc_2/lib/json_rpc_2.dart
pkgs/json_rpc_2/lib/src/client.dart
pkgs/json_rpc_2/lib/src/exception.dart
pkgs/json_rpc_2/lib/src/parameters.dart
pkgs/json_rpc_2/lib/src/peer.dart
pkgs/json_rpc_2/lib/src/server.dart
pkgs/json_rpc_2/lib/src/utils.dart
pkgs/json_rpc_2/test/client/client_test.dart
pkgs/json_rpc_2/test/client/stream_test.dart
pkgs/json_rpc_2/test/client/utils.dart
pkgs/json_rpc_2/test/peer_test.dart
pkgs/json_rpc_2/test/server/batch_test.dart
pkgs/json_rpc_2/test/server/invalid_request_test.dart
pkgs/json_rpc_2/test/server/parameters_test.dart
pkgs/json_rpc_2/test/server/server_test.dart
pkgs/json_rpc_2/test/server/stream_test.dart
pkgs/json_rpc_2/test/server/utils.dart
pkgs/mime/example/example.dart
pkgs/mime/lib/mime.dart
pkgs/mime/lib/src/bound_multipart_stream.dart
pkgs/mime/lib/src/char_code.dart
pkgs/mime/lib/src/default_extension_map.dart
pkgs/mime/lib/src/extension.dart
pkgs/mime/lib/src/magic_number.dart
pkgs/mime/lib/src/mime_shared.dart
pkgs/mime/lib/src/mime_type.dart
pkgs/mime/lib/src/multipart_transformer.dart
pkgs/mime/test/default_extension_map_test.dart
pkgs/mime/test/extension_test.dart
pkgs/mime/test/mime_multipart_transformer_test.dart
pkgs/mime/test/mime_type_test.dart
pkgs/mime/tool/download_mime_info.dart
pkgs/mime/tool/regenerate_tables.dart
pkgs/oauth2/example/main.dart
pkgs/oauth2/lib/src/authorization_exception.dart
pkgs/oauth2/lib/src/expiration_exception.dart
pkgs/oauth2/lib/src/handle_access_token_response.dart
pkgs/oauth2/lib/src/parameters.dart
pkgs/oauth2/lib/src/resource_owner_password_grant.dart
pkgs/oauth2/test/authorization_code_grant_test.dart
pkgs/oauth2/test/client_credentials_grant_test.dart
pkgs/oauth2/test/client_test.dart
pkgs/oauth2/test/credentials_test.dart
pkgs/oauth2/test/handle_access_token_response_test.dart
pkgs/oauth2/test/resource_owner_password_grant_test.dart
pkgs/oauth2/test/utils.dart
pkgs/package_config/bin/package_config_of.dart
pkgs/package_config/example/main.dart
pkgs/package_config/lib/package_config.dart
pkgs/package_config/lib/package_config_types.dart
pkgs/package_config/lib/src/discovery.dart
pkgs/package_config/lib/src/errors.dart
pkgs/package_config/lib/src/package_config.dart
pkgs/package_config/lib/src/package_config_io.dart
pkgs/package_config/lib/src/util.dart
pkgs/package_config/lib/src/util_io.dart
pkgs/package_config/test/bench.dart
pkgs/package_config/test/discovery_test.dart
pkgs/package_config/test/discovery_uri_test.dart
pkgs/package_config/test/package_config_impl_test.dart
pkgs/package_config/test/src/util_io.dart
pkgs/pool/benchmark/for_each_benchmark.dart
pkgs/pool/lib/pool.dart
pkgs/pool/test/pool_test.dart
pkgs/process/example/main.dart
pkgs/process/lib/process.dart
pkgs/process/lib/src/interface/common.dart
pkgs/process/lib/src/interface/exceptions.dart
pkgs/process/lib/src/interface/local_process_manager.dart
pkgs/process/lib/src/interface/process_manager.dart
pkgs/process/lib/src/interface/process_wrapper.dart
pkgs/process/test/src/interface/common_test.dart
pkgs/process/test/src/interface/process_wrapper_test.dart
pkgs/process/test/utils.dart
pkgs/pub_semver/example/example.dart
pkgs/pub_semver/lib/pub_semver.dart
pkgs/pub_semver/lib/src/patterns.dart
pkgs/pub_semver/lib/src/utils.dart
pkgs/pub_semver/lib/src/version.dart
pkgs/pub_semver/lib/src/version_constraint.dart
pkgs/pub_semver/lib/src/version_range.dart
pkgs/pub_semver/lib/src/version_union.dart
pkgs/pub_semver/test/utils.dart
pkgs/pub_semver/test/version_constraint_test.dart
pkgs/pub_semver/test/version_range_test.dart
pkgs/pub_semver/test/version_test.dart
pkgs/pub_semver/test/version_union_test.dart
pkgs/pubspec_parse/lib/pubspec_parse.dart
pkgs/pubspec_parse/lib/src/dependency.dart
pkgs/pubspec_parse/lib/src/pubspec.dart
pkgs/pubspec_parse/lib/src/screenshot.dart
pkgs/pubspec_parse/test/dependency_test.dart
pkgs/pubspec_parse/test/ensure_build_test.dart
pkgs/pubspec_parse/test/git_uri_test.dart
pkgs/pubspec_parse/test/pub_utils.dart
pkgs/pubspec_parse/test/test_utils.dart
pkgs/pubspec_parse/test/tojson_test.dart
pkgs/source_map_stack_trace/lib/source_map_stack_trace.dart
pkgs/source_map_stack_trace/test/source_map_stack_trace_test.dart
pkgs/source_maps/lib/builder.dart
pkgs/source_maps/lib/parser.dart
pkgs/source_maps/lib/refactor.dart
pkgs/source_maps/lib/source_maps.dart
pkgs/source_maps/lib/src/source_map_span.dart
pkgs/source_maps/lib/src/utils.dart
pkgs/source_maps/lib/src/vlq.dart
pkgs/source_maps/test/builder_test.dart
pkgs/source_maps/test/common.dart
pkgs/source_maps/test/continued_region_test.dart
pkgs/source_maps/test/end2end_test.dart
pkgs/source_maps/test/parser_test.dart
pkgs/source_maps/test/printer_test.dart
pkgs/source_maps/test/refactor_test.dart
pkgs/source_maps/test/utils_test.dart
pkgs/source_maps/test/vlq_test.dart
pkgs/source_span/example/main.dart
pkgs/source_span/lib/source_span.dart
pkgs/source_span/lib/src/charcode.dart
pkgs/source_span/lib/src/colors.dart
pkgs/source_span/lib/src/file.dart
pkgs/source_span/lib/src/highlighter.dart
pkgs/source_span/lib/src/location.dart
pkgs/source_span/lib/src/location_mixin.dart
pkgs/source_span/lib/src/span.dart
pkgs/source_span/lib/src/span_exception.dart
pkgs/source_span/lib/src/span_mixin.dart
pkgs/source_span/lib/src/span_with_context.dart
pkgs/source_span/lib/src/utils.dart
pkgs/source_span/test/file_benchmark.dart
pkgs/source_span/test/file_test.dart
pkgs/source_span/test/location_test.dart
pkgs/source_span/test/utils_test.dart
pkgs/sse/example/index.dart
pkgs/sse/example/server.dart
pkgs/sse/lib/client/sse_client.dart
pkgs/sse/lib/server/sse_handler.dart
pkgs/sse/lib/src/server/sse_handler.dart
pkgs/sse/lib/src/util/id.dart
pkgs/sse/test/sse_test.dart
pkgs/sse/test/sse_unit_test.dart
pkgs/sse/test/web/index.dart
pkgs/stack_trace/example/example.dart
pkgs/stack_trace/lib/src/chain.dart
pkgs/stack_trace/lib/src/frame.dart
pkgs/stack_trace/lib/src/lazy_chain.dart
pkgs/stack_trace/lib/src/lazy_trace.dart
pkgs/stack_trace/lib/src/stack_zone_specification.dart
pkgs/stack_trace/lib/src/trace.dart
pkgs/stack_trace/lib/src/unparsed_frame.dart
pkgs/stack_trace/lib/src/utils.dart
pkgs/stack_trace/lib/src/vm_trace.dart
pkgs/stack_trace/lib/stack_trace.dart
pkgs/stack_trace/test/chain/chain_test.dart
pkgs/stack_trace/test/chain/dart2js_test.dart
pkgs/stack_trace/test/chain/utils.dart
pkgs/stack_trace/test/chain/vm_test.dart
pkgs/stack_trace/test/frame_test.dart
pkgs/stack_trace/test/trace_test.dart
pkgs/stack_trace/test/utils.dart
pkgs/stack_trace/test/vm_test.dart
pkgs/stream_channel/example/example.dart
pkgs/stream_channel/lib/isolate_channel.dart
pkgs/stream_channel/lib/src/close_guarantee_channel.dart
pkgs/stream_channel/lib/src/delegating_stream_channel.dart
pkgs/stream_channel/lib/src/disconnector.dart
pkgs/stream_channel/lib/src/guarantee_channel.dart
pkgs/stream_channel/lib/src/isolate_channel.dart
pkgs/stream_channel/lib/src/json_document_transformer.dart
pkgs/stream_channel/lib/src/multi_channel.dart
pkgs/stream_channel/lib/src/stream_channel_completer.dart
pkgs/stream_channel/lib/src/stream_channel_controller.dart
pkgs/stream_channel/lib/src/stream_channel_transformer.dart
pkgs/stream_channel/lib/stream_channel.dart
pkgs/stream_channel/test/disconnector_test.dart
pkgs/stream_channel/test/isolate_channel_test.dart
pkgs/stream_channel/test/json_document_transformer_test.dart
pkgs/stream_channel/test/multi_channel_test.dart
pkgs/stream_channel/test/stream_channel_completer_test.dart
pkgs/stream_channel/test/stream_channel_controller_test.dart
pkgs/stream_channel/test/stream_channel_test.dart
pkgs/stream_channel/test/with_close_guarantee_test.dart
pkgs/stream_channel/test/with_guarantees_test.dart
pkgs/stream_transform/example/main.dart
pkgs/stream_transform/lib/src/aggregate_sample.dart
pkgs/stream_transform/lib/src/async_expand.dart
pkgs/stream_transform/lib/src/async_map.dart
pkgs/stream_transform/lib/src/combine_latest.dart
pkgs/stream_transform/lib/src/common_callbacks.dart
pkgs/stream_transform/lib/src/concatenate.dart
pkgs/stream_transform/lib/src/from_handlers.dart
pkgs/stream_transform/lib/src/merge.dart
pkgs/stream_transform/lib/src/rate_limit.dart
pkgs/stream_transform/lib/src/scan.dart
pkgs/stream_transform/lib/src/switch.dart
pkgs/stream_transform/lib/src/take_until.dart
pkgs/stream_transform/lib/src/tap.dart
pkgs/stream_transform/lib/src/where.dart
pkgs/stream_transform/lib/stream_transform.dart
pkgs/stream_transform/test/async_expand_test.dart
pkgs/stream_transform/test/async_map_buffer_test.dart
pkgs/stream_transform/test/async_map_sample_test.dart
pkgs/stream_transform/test/async_where_test.dart
pkgs/stream_transform/test/audit_test.dart
pkgs/stream_transform/test/buffer_test.dart
pkgs/stream_transform/test/combine_latest_all_test.dart
pkgs/stream_transform/test/combine_latest_test.dart
pkgs/stream_transform/test/concurrent_async_map_test.dart
pkgs/stream_transform/test/debounce_test.dart
pkgs/stream_transform/test/followd_by_test.dart
pkgs/stream_transform/test/from_handlers_test.dart
pkgs/stream_transform/test/merge_test.dart
pkgs/stream_transform/test/sample_test.dart
pkgs/stream_transform/test/scan_test.dart
pkgs/stream_transform/test/start_with_test.dart
pkgs/stream_transform/test/switch_test.dart
pkgs/stream_transform/test/take_until_test.dart
pkgs/stream_transform/test/tap_test.dart
pkgs/stream_transform/test/throttle_test.dart
pkgs/stream_transform/test/utils.dart
pkgs/stream_transform/test/where_not_null_test.dart
pkgs/stream_transform/test/where_type_test.dart
pkgs/string_scanner/example/example.dart
pkgs/string_scanner/lib/src/charcode.dart
pkgs/string_scanner/lib/src/eager_span_scanner.dart
pkgs/string_scanner/lib/src/exception.dart
pkgs/string_scanner/lib/src/line_scanner.dart
pkgs/string_scanner/lib/src/relative_span_scanner.dart
pkgs/string_scanner/lib/src/span_scanner.dart
pkgs/string_scanner/lib/src/utils.dart
pkgs/string_scanner/lib/string_scanner.dart
pkgs/string_scanner/test/error_test.dart
pkgs/string_scanner/test/line_scanner_test.dart
pkgs/string_scanner/test/span_scanner_test.dart
pkgs/string_scanner/test/string_scanner_test.dart
pkgs/string_scanner/test/utils.dart
pkgs/term_glyph/lib/term_glyph.dart
pkgs/term_glyph/test/symbol_test.dart
pkgs/term_glyph/tool/generate.dart
pkgs/test_reflective_loader/lib/test_reflective_loader.dart
pkgs/test_reflective_loader/test/hierarchy_test.dart
pkgs/test_reflective_loader/test/hierarchy_test.data.dart
pkgs/test_reflective_loader/test/location_test.dart
pkgs/test_reflective_loader/test/test_reflective_loader_test.dart
pkgs/timing/lib/src/clock.dart
pkgs/timing/lib/src/timing.dart
pkgs/timing/lib/timing.dart
pkgs/timing/test/timing_test.dart
pkgs/unified_analytics/example/log_stats.dart
pkgs/unified_analytics/example/sample_rate.dart
pkgs/unified_analytics/example/serving_surveys.dart
pkgs/unified_analytics/example/unified_analytics_example.dart
pkgs/unified_analytics/lib/src/analytics.dart
pkgs/unified_analytics/lib/src/asserts.dart
pkgs/unified_analytics/lib/src/config_handler.dart
pkgs/unified_analytics/lib/src/constants.dart
pkgs/unified_analytics/lib/src/enums.dart
pkgs/unified_analytics/lib/src/event.dart
pkgs/unified_analytics/lib/src/ga_client.dart
pkgs/unified_analytics/lib/src/initializer.dart
pkgs/unified_analytics/lib/src/log_handler.dart
pkgs/unified_analytics/lib/src/survey_handler.dart
pkgs/unified_analytics/lib/src/user_property.dart
pkgs/unified_analytics/lib/src/utils.dart
pkgs/unified_analytics/lib/testing.dart
pkgs/unified_analytics/lib/unified_analytics.dart
pkgs/unified_analytics/test/asserts_test.dart
pkgs/unified_analytics/test/error_handler_test.dart
pkgs/unified_analytics/test/event_test.dart
pkgs/unified_analytics/test/events_with_fake_test.dart
pkgs/unified_analytics/test/legacy_analytics_test.dart
pkgs/unified_analytics/test/log_handler_test.dart
pkgs/unified_analytics/test/no_op_analytics_test.dart
pkgs/unified_analytics/test/suppression_test.dart
pkgs/unified_analytics/test/survey_handler_test.dart
pkgs/unified_analytics/test/unified_analytics_test.dart
pkgs/unified_analytics/test/workflow_test.dart
pkgs/watcher/example/watch.dart
pkgs/watcher/lib/src/async_queue.dart
pkgs/watcher/lib/src/custom_watcher_factory.dart
pkgs/watcher/lib/src/directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/linux/linux_directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/linux/native_watch.dart
pkgs/watcher/lib/src/directory_watcher/linux/watch_tree.dart
pkgs/watcher/lib/src/directory_watcher/linux/watch_tree_root.dart
pkgs/watcher/lib/src/directory_watcher/polling/directory_list.dart
pkgs/watcher/lib/src/directory_watcher/polling/polling_directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/recursive/directory_tree.dart
pkgs/watcher/lib/src/directory_watcher/recursive/event_tree.dart
pkgs/watcher/lib/src/directory_watcher/recursive/isolate_recursive_directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/recursive/recursive_directory_watcher.dart
pkgs/watcher/lib/src/directory_watcher/recursive/recursive_native_watch.dart
pkgs/watcher/lib/src/directory_watcher/recursive/watched_directory_tree.dart
pkgs/watcher/lib/src/event.dart
pkgs/watcher/lib/src/event_batching.dart
pkgs/watcher/lib/src/file_watcher.dart
pkgs/watcher/lib/src/file_watcher/native.dart
pkgs/watcher/lib/src/file_watcher/polling.dart
pkgs/watcher/lib/src/paths.dart
pkgs/watcher/lib/src/polling.dart
pkgs/watcher/lib/src/resubscribable.dart
pkgs/watcher/lib/src/testing.dart
pkgs/watcher/lib/src/watch_event.dart
pkgs/watcher/lib/watcher.dart
pkgs/watcher/test/custom_watcher_factory_test.dart
pkgs/watcher/test/directory_watcher/client_simulator.dart
pkgs/watcher/test/directory_watcher/end_to_end_test_runner.dart
pkgs/watcher/test/directory_watcher/end_to_end_tests.dart
pkgs/watcher/test/directory_watcher/file_changer.dart
pkgs/watcher/test/directory_watcher/file_tests.dart
pkgs/watcher/test/directory_watcher/link_tests.dart
pkgs/watcher/test/directory_watcher/linux_test.dart
pkgs/watcher/test/directory_watcher/macos_test.dart
pkgs/watcher/test/directory_watcher/polling/directory_list_test.dart
pkgs/watcher/test/directory_watcher/polling_test.dart
pkgs/watcher/test/directory_watcher/recursive/event_tree_test.dart
pkgs/watcher/test/directory_watcher/relative_directory_test.dart
pkgs/watcher/test/directory_watcher/windows_isolate_test.dart
pkgs/watcher/test/directory_watcher/windows_test.dart
pkgs/watcher/test/event_batching_test.dart
pkgs/watcher/test/file_watcher/file_tests.dart
pkgs/watcher/test/file_watcher/link_tests.dart
pkgs/watcher/test/file_watcher/native_test.dart
pkgs/watcher/test/file_watcher/polling_test.dart
pkgs/watcher/test/file_watcher/startup_race_tests.dart
pkgs/watcher/test/no_subscription/linux_test.dart
pkgs/watcher/test/no_subscription/macos_test.dart
pkgs/watcher/test/no_subscription/polling_test.dart
pkgs/watcher/test/no_subscription/shared.dart
pkgs/watcher/test/no_subscription/windows_test.dart
pkgs/watcher/test/paths_test.dart
pkgs/watcher/test/ready/linux_test.dart
pkgs/watcher/test/ready/macos_test.dart
pkgs/watcher/test/ready/polling_test.dart
pkgs/watcher/test/ready/shared.dart
pkgs/watcher/test/ready/windows_test.dart
pkgs/watcher/test/utils.dart
pkgs/yaml/benchmark/benchmark.dart
pkgs/yaml/example/example.dart
pkgs/yaml/lib/src/charcodes.dart
pkgs/yaml/lib/src/equality.dart
pkgs/yaml/lib/src/error_listener.dart
pkgs/yaml/lib/src/event.dart
pkgs/yaml/lib/src/loader.dart
pkgs/yaml/lib/src/null_span.dart
pkgs/yaml/lib/src/parser.dart
pkgs/yaml/lib/src/scanner.dart
pkgs/yaml/lib/src/style.dart
pkgs/yaml/lib/src/token.dart
pkgs/yaml/lib/src/utils.dart
pkgs/yaml/lib/src/yaml_document.dart
pkgs/yaml/lib/src/yaml_exception.dart
pkgs/yaml/lib/src/yaml_node.dart
pkgs/yaml/lib/src/yaml_node_wrapper.dart
pkgs/yaml/lib/yaml.dart
pkgs/yaml/test/span_test.dart
pkgs/yaml/test/utils.dart
pkgs/yaml/test/yaml_node_wrapper_test.dart
pkgs/yaml_edit/example/example.dart
pkgs/yaml_edit/example/json2yaml.dart
pkgs/yaml_edit/lib/src/editor.dart
pkgs/yaml_edit/lib/src/equality.dart
pkgs/yaml_edit/lib/src/errors.dart
pkgs/yaml_edit/lib/src/list_mutations.dart
pkgs/yaml_edit/lib/src/map_mutations.dart
pkgs/yaml_edit/lib/src/source_edit.dart
pkgs/yaml_edit/lib/src/strings.dart
pkgs/yaml_edit/lib/src/utils.dart
pkgs/yaml_edit/lib/src/wrap.dart
pkgs/yaml_edit/lib/yaml_edit.dart
pkgs/yaml_edit/test/alias_test.dart
pkgs/yaml_edit/test/append_test.dart
pkgs/yaml_edit/test/crash_test/crash_test.dart
pkgs/yaml_edit/test/editor_test.dart
pkgs/yaml_edit/test/golden_test.dart
pkgs/yaml_edit/test/insert_test.dart
pkgs/yaml_edit/test/naughty_test.dart
pkgs/yaml_edit/test/parse_test.dart
pkgs/yaml_edit/test/prepend_test.dart
pkgs/yaml_edit/test/preservation_test.dart
pkgs/yaml_edit/test/problem_strings.dart
pkgs/yaml_edit/test/random_test.dart
pkgs/yaml_edit/test/remove_test.dart
pkgs/yaml_edit/test/source_edit_test.dart
pkgs/yaml_edit/test/special_test.dart
pkgs/yaml_edit/test/splice_test.dart
pkgs/yaml_edit/test/string_test.dart
pkgs/yaml_edit/test/test_case.dart
pkgs/yaml_edit/test/test_utils.dart
pkgs/yaml_edit/test/update_test.dart
pkgs/yaml_edit/test/windows_test.dart
pkgs/yaml_edit/test/wrap_test.dart
tool/readme_update.dart

This check can be disabled by tagging the PR with skip-license-check.

API leaks ✔️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbol Leaking sources

This check can be disabled by tagging the PR with skip-leaking-check.

@pavelgj
Copy link
Copy Markdown
Author

pavelgj commented Mar 3, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several valuable OAuth 2.0 features, including server discovery, dynamic client registration, resource indicators, and custom client authenticators. A critical security vulnerability has been identified due to a lack of HTTPS enforcement for the discovery and registration endpoints, which is mandated by RFC 8414, RFC 9728, and RFC 7591 to prevent Man-in-the-Middle attacks. It is recommended to add checks to ensure these URLs use the https scheme. Furthermore, there are opportunities to improve maintainability by refactoring duplicated code blocks.

Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/registration.dart
@jonasfj jonasfj self-requested a review March 3, 2026 17:47
@pavelgj
Copy link
Copy Markdown
Author

pavelgj commented Mar 3, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new features to the oauth2 package, including support for OAuth 2.0 discovery, dynamic client registration, resource indicators, and custom client authenticators. A comprehensive security audit found no vulnerabilities, and the changes adhere to OAuth 2.0 security best practices. My review focuses on improving code maintainability by reducing duplication and ensuring adherence to the repository's style guide regarding documentation for public members.

Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/registration.dart
Comment thread pkgs/oauth2/lib/src/registration.dart
@pavelgj
Copy link
Copy Markdown
Author

pavelgj commented Mar 3, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new functionality to the oauth2 package, including support for OAuth 2.0 discovery, dynamic client registration, resource indicators, and custom authenticators. A critical security weakness was identified in the discoverProtectedResourceMetadata function, where an optional metadata URL is not checked for the https scheme, potentially allowing SSRF to internal http endpoints. This must be addressed to comply with RFC 9728 and improve security. Furthermore, general feedback includes improving code maintainability by reducing duplication, fixing a minor bug in the discovery logic, and enhancing documentation for the new public APIs to align with the repository's style guide.

Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/discovery.dart Outdated
Comment thread pkgs/oauth2/lib/src/registration.dart
…iscovery and registration function documentation.
@pavelgj
Copy link
Copy Markdown
Author

pavelgj commented Mar 3, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new functionality to package:oauth2, including support for OAuth 2.0 discovery, dynamic client registration, resource indicators, and custom client authenticators. The changes are well-structured and include comprehensive tests for the new features.

My review has identified a couple of areas for improvement:

  • A bug in the URL comparison logic for issuer and resource validation in the discovery mechanism, which could lead to incorrect spoofing detection.
  • Opportunities to refactor duplicated code in client_credentials_grant.dart and credentials.dart to improve maintainability.

Overall, this is a great contribution that significantly enhances the capabilities of the package. Addressing the points above will make the implementation more robust and maintainable.

Comment thread pkgs/oauth2/lib/src/discovery.dart Outdated
Comment thread pkgs/oauth2/lib/src/discovery.dart Outdated
Copy link
Copy Markdown
Member

@jonasfj jonasfj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly, just nits

Comment thread pkgs/oauth2/lib/src/registration.dart Outdated
Comment thread pkgs/oauth2/lib/src/registration.dart Outdated
Comment thread pkgs/oauth2/lib/src/registration.dart Outdated
Comment thread pkgs/oauth2/lib/src/registration.dart Outdated
Comment thread pkgs/oauth2/lib/src/registration.dart
Comment thread pkgs/oauth2/lib/src/discovery.dart Outdated
Comment thread pkgs/oauth2/lib/src/registration.dart
Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/discovery.dart Outdated
Comment thread pkgs/oauth2/lib/src/authorization_code_grant.dart
Copy link
Copy Markdown
Member

@jonasfj jonasfj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly, just nits

Copy link
Copy Markdown
Member

@jonasfj jonasfj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly just nits

pavelgj and others added 2 commits March 3, 2026 14:20
…before comparison to prevent spoofing detection issues.
Co-authored-by: Jonas Finnemann Jensen <jopsen@gmail.com>
pavelgj and others added 7 commits March 3, 2026 14:21
Co-authored-by: Jonas Finnemann Jensen <jopsen@gmail.com>
Co-authored-by: Jonas Finnemann Jensen <jopsen@gmail.com>
Co-authored-by: Jonas Finnemann Jensen <jopsen@gmail.com>
Co-authored-by: Jonas Finnemann Jensen <jopsen@gmail.com>
Co-authored-by: Jonas Finnemann Jensen <jopsen@gmail.com>
Co-authored-by: Jonas Finnemann Jensen <jopsen@gmail.com>
Comment thread pkgs/oauth2/lib/src/utils.dart Outdated
@pavelgj
Copy link
Copy Markdown
Author

pavelgj commented Mar 5, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new features to the oauth2 package, including support for OAuth 2.0 discovery, dynamic client registration, resource indicators, and custom client authenticators. The changes are well-structured and include comprehensive tests for the new functionality. My review focuses on improving code maintainability by reducing duplication and enhancing documentation to align with the repository's style guide.

Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/discovery.dart
Comment thread pkgs/oauth2/lib/src/registration.dart
Comment thread pkgs/oauth2/lib/src/registration.dart
@pavelgj
Copy link
Copy Markdown
Author

pavelgj commented Mar 5, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new features to the oauth2 package, including support for OAuth 2.0 discovery, dynamic client registration, resource indicators, and custom client authenticators. The changes are extensive and well-tested. My review focuses on improving code maintainability by reducing duplication in the new logic for handling resource indicators, and ensuring the documentation for the new discovery feature accurately reflects its behavior and adheres to DartDoc style guidelines.

Comment thread pkgs/oauth2/lib/src/discovery.dart Outdated
…y error handling and fallback behavior for invalid responses.
@pavelgj
Copy link
Copy Markdown
Author

pavelgj commented Mar 5, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant new features to package:oauth2, including support for server discovery, dynamic client registration, resource indicators, and custom client authenticators. The implementation is generally of high quality and includes comprehensive tests for the new functionality.

My review focuses on a few areas for improvement:

  • Documentation: Several new public parameters (resources) are missing DartDoc comments, which is required by the repository's style guide.
  • Code Duplication: There are opportunities to refactor duplicated logic in credentials.dart and client_credentials_grant.dart to improve maintainability.
  • Bug Fix: There is a bug in the server discovery logic where it doesn't correctly fall back to other discovery URLs upon certain errors, which contradicts the documented behavior.

Overall, this is a great contribution. Addressing these points will further improve the code quality.

Comment on lines +213 to +214
if (e is DiscoveryException) rethrow;
continue;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The rethrow statement for DiscoveryException will cause the discovery process to terminate immediately instead of trying the next fallback URL. This contradicts the function's documentation, which states: "If a metadata endpoint is found but returns an invalid response (e.g., malformed JSON or issuer spoofing is detected), the function will catch the resulting exception and automatically try the next fallback URL."

An issuer spoofing check throws a DiscoveryException, and invalid JSON throws a FormatException. Both should be caught and allow the loop to continue to the next discovery URL. To fix this and align with the documentation, you should allow the catch block to always continue.

Suggested change
if (e is DiscoveryException) rethrow;
continue;
continue;

Comment on lines 198 to +199
Uri getAuthorizationUrl(Uri redirect,
{Iterable<String>? scopes, String? state}) {
{Iterable<String>? scopes, String? state, Iterable<Uri>? resources}) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The new resources parameter in getAuthorizationUrl is not documented. According to the repository's style guide, all public members should be documented. Please add documentation for this new parameter to explain its purpose, which is for RFC 8707 Resource Indicators.

References
  1. At least all public members should have documentation, answering the why. (link)

Comment on lines 50 to 59
Future<Client> clientCredentialsGrant(
Uri authorizationEndpoint, String? identifier, String? secret,
{Iterable<String>? scopes,
bool basicAuth = true,
http.Client? httpClient,
String? delimiter,
ClientAuthenticator? customAuth,
Iterable<Uri>? resources,
Map<String, dynamic> Function(MediaType? contentType, String body)?
getParameters}) async {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The new resources parameter in clientCredentialsGrant is not documented. The repository style guide requires all public members to be documented. Please add documentation for this parameter to explain its purpose, which is for RFC 8707 Resource Indicators.

References
  1. At least all public members should have documentation, answering the why. (link)

Comment on lines +83 to +109
if (resources != null && resources.isNotEmpty) {
// http.post doesn't support Map<String, Iterable> for x-www-form-urlencoded
// bodies, so we construct the body string manually to allow
// multiple 'resource' parameters per RFC 8707.
final encodedBody = body.entries
.map((e) => '${Uri.encodeQueryComponent(e.key)}='
'${Uri.encodeQueryComponent(e.value)}')
.toList();
for (final r in resources) {
encodedBody.add('resource=${Uri.encodeQueryComponent(r.toString())}');
}

httpClient ??= http.Client();
var response = await httpClient.post(authorizationEndpoint,
headers: headers
..['content-type'] = 'application/x-www-form-urlencoded',
body: encodedBody.join('&'));

var credentials = handleAccessTokenResponse(response, authorizationEndpoint,
startTime, scopes?.toList() ?? [], delimiter,
getParameters: getParameters);
return Client(credentials,
identifier: identifier,
secret: secret,
httpClient: httpClient,
customAuth: customAuth);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This if block for handling resources duplicates a lot of logic from the code that follows it (lines 111-123). Both branches make an HTTP POST request, handle the access token response, and create a Client. This duplication can lead to maintenance issues.

Please consider refactoring to remove the duplication. You could, for instance, determine the request body and content-type first, and then have a single path for making the request and processing the response.

Comment on lines +266 to +287
if (resources != null && resources.isNotEmpty) {
final encodedBody = body.entries
.map((e) => '${Uri.encodeQueryComponent(e.key)}='
'${Uri.encodeQueryComponent(e.value)}')
.toList();
for (final r in resources) {
encodedBody.add('resource=${Uri.encodeQueryComponent(r.toString())}');
}
headers['content-type'] = 'application/x-www-form-urlencoded';
var response = await httpClient.post(tokenEndpoint,
headers: headers, body: encodedBody.join('&'));
var credentials = handleAccessTokenResponse(
response, tokenEndpoint, startTime, scopes, _delimiter,
getParameters: _getParameters);
if (credentials.refreshToken != null) return credentials;
return Credentials(credentials.accessToken,
refreshToken: refreshToken,
idToken: credentials.idToken,
tokenEndpoint: credentials.tokenEndpoint,
scopes: credentials.scopes,
expiration: credentials.expiration);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is significant code duplication between this block that handles requests with resources and the following code that handles requests without them. Both branches perform an HTTP POST, handle the response, and construct a Credentials object. This duplication makes the code harder to maintain.

Consider refactoring to unify the logic. For example, you could prepare the request body (either as a Map<String, String> or an encoded String) and then have a single httpClient.post call and a single block for response handling.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But is this code really that complicated.. we're implementing a spec, this won't be touched much. And abstractions might just make everything weirder..

Straight lines of code is awesome.. too many fancy private methods trying to share trivial logic doesn't make the world better.

Copy link
Copy Markdown
Member

@jonasfj jonasfj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no major concerns. @pavelgj do you need this published soon?

/// Adds additional query parameters to [url], overwriting the original
/// parameters if a name conflict occurs.
Uri addQueryParameters(Uri url, Map<String, String> parameters) => url.replace(
Uri addQueryParameters(Uri url, Map<String, dynamic> parameters) => url.replace(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why dynamic?

@kevmoo
Copy link
Copy Markdown
Member

kevmoo commented Mar 10, 2026

please comment/resolve the gemini comments, too. I've found they are solid at least 3/4 of the time

@kevmoo
Copy link
Copy Markdown
Member

kevmoo commented Mar 28, 2026

@pavelgj – wanna run with the remaining comments?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants