Skip to content

Register custom OIDC scopes order-independently#4

Merged
chiiya merged 1 commit into
masterfrom
feature/custom-scope-registration
Jun 16, 2026
Merged

Register custom OIDC scopes order-independently#4
chiiya merged 1 commit into
masterfrom
feature/custom-scope-registration

Conversation

@chiiya

@chiiya chiiya commented Jun 16, 2026

Copy link
Copy Markdown
Member

Why

Custom OIDC scopes could only be added by racing service-provider boot order. The package snapshots the scope registry into Passport::tokensCan() during its own packageBooted(), so a scope a host app registered later never became requestable. Consumers had to reach into the container with an afterResolving(ScopeRegistrar::class, …) hook installed in register() — a workaround every consumer would otherwise need.

The ClaimAggregator and DefaultDiscoveryBuilder were already correct (they read the ScopeRegistrar live at request time); only the Passport snapshot was order-sensitive.

What

  • Defer the Passport snapshot to app->booted() so it runs after every provider has booted. Scopes registered from any provider, in any order, are now captured.
  • Add Identity::registerScope(string $scope, array $claims) — a public API that buffers into Identity::$scopes and is flushed into the ScopeRegistrar during boot. Safe to call from register() or boot().
  • The buffer flush (applyCustomScopes()) runs unconditionally; only the Passport::tokensCan() snapshot stays gated by register_openid_scope, so apps managing Passport scopes themselves still get custom scopes into discovery and claim filtering.

Tests

CustomScopeRegistrationTest loads a fixture provider after laravel-identity and asserts the scope lands in Passport::scopes(), the discovery document (scopes_supported + claims_supported), and ScopeRegistrar::claimsFor() — failing if boot-order coupling ever returns.

Full suite: 72 passing. Lint (ecs/php-cs-fixer/rector/tlint) clean.

Docs

README updated to document Identity::registerScope() and drop the old app->extend() scope-registration example.

Snapshotting the scope registry into Passport::tokensCan() ran during
the package boot, so a host app could only add custom scopes by racing
provider boot order. Defer the snapshot to app booted() and add
Identity::registerScope() so scopes registered from any provider reach
Passport, discovery, and claim filtering regardless of order.
@chiiya chiiya merged commit 18c55a2 into master Jun 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant