Skip to content

Return granted scope on token exchange, fix solving-times:write role check - #184

Open
puzzlerushse wants to merge 1 commit into
MySpeedPuzzling:mainfrom
puzzlerushse:fix/oauth-token-response-missing-scope
Open

Return granted scope on token exchange, fix solving-times:write role check#184
puzzlerushse wants to merge 1 commit into
MySpeedPuzzling:mainfrom
puzzlerushse:fix/oauth-token-response-missing-scope

Conversation

@puzzlerushse

Copy link
Copy Markdown

Summary

Two independent, small fixes bundled together since they touch the same file group:

1. Token response never includes granted scope

league/oauth2-server's default response never includes which scopes were actually granted (BearerTokenResponse::getExtraParams returns []). Nothing wrong with that as shipped, but a consuming app that wants to detect a stale, pre-scope-expansion authorization (e.g. re-checking for a write scope before attempting a write, rather than attempting a call that will 403) has nothing to check the response against.

ScopeAwareBearerTokenResponse adds the scope back via the response_type_class extension point already supported by league/oauth2-server-bundle. It's picked up automatically by the existing Security/** service glob in config/services.php — no explicit service registration needed.

2. Wrong role name checked for solving-times:write

CreateSolvingTimeInput/UpdateSolvingTimeInput's write-scope security check compares against ROLE_OAUTH2_SOLVING_TIMES:WRITE (underscore), but the role oauth2-server actually grants is built by uppercasing the scope string verbatim (OAuth2Token.php: strtoupper($rolePrefix . $scope), no punctuation normalization) — so a solving-times:write scope produces ROLE_OAUTH2_SOLVING-TIMES:WRITE (hyphen).

solving-times is the only hyphenated scope in the system, which is presumably why this was never caught — nothing else has ever exercised this exact path. An OAuth-scope-authenticated write to /me/solving-times has likely never worked; PAT-based writes are unaffected (ROLE_PAT is checked independently in the same or expression).

Test plan

  • Confirm a client-credentials/auth-code token issued with solving-times:write can now successfully POST/PUT /api/v1/me/solving-times
  • Confirm the token exchange response (/oauth2/token) now includes a scope field listing the granted scopes

…check

league/oauth2-server's default token response never includes which
scopes were actually granted (BearerTokenResponse::getExtraParams
returns []). Nothing wrong with that as shipped, but a consuming app
that wants to detect a stale, pre-scope-expansion authorization (e.g.
re-checking for a write scope before attempting a write, rather than
attempting a call that will 403) has nothing to check the response
against. ScopeAwareBearerTokenResponse adds the scope back via the
response_type_class extension point already supported by
league/oauth2-server-bundle - picked up automatically by the existing
Security/** service glob in config/services.php, no explicit service
registration needed.

Bundled with a related but independent bug in already-shipped code:
CreateSolvingTimeInput/UpdateSolvingTimeInput's write-scope security
check compares against ROLE_OAUTH2_SOLVING_TIMES:WRITE (underscore),
but the role oauth2-server actually grants is built by uppercasing the
scope string verbatim (OAuth2Token.php: strtoupper($rolePrefix .
$scope), no punctuation normalization) - so a solving-times:write
scope produces ROLE_OAUTH2_SOLVING-TIMES:WRITE (hyphen). solving-times
is the only hyphenated scope in the system, which is presumably why
this was never caught: nothing else has ever exercised this path.
An OAuth-scope-authenticated write to /me/solving-times has likely
never worked; PAT-based writes are unaffected (ROLE_PAT is checked
independently).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant