Repository navigation
feat(auth): fine-grained OAuth scope grants and consent records (#250) - #768
Merged
Merged
Conversation
- ExternalLogin gains GrantedScopes (JSON array), ConsentedAt and
ConsentVersion (OAuthConsentVersions.Current = 1); additive migration.
- OAuthService.ResolveAuthorizationScopes single-sources the exact scope
list authorization URLs embed; link (Google/Discord), callback and
sign-in auto-link paths persist it with a consent stamp, re-recording
consent only when the scope set changed (first-consent preserved).
- HEAD /v1/auth/external-logins now also emits X-Granted-Scopes:
'provider=iso-consent-timestamp|consent-version|url-encoded-scopes'.
- New GET /auth/external-logins/{provider}/link-preview (authorization-
time consent screen data) and POST .../scopes:revoke (per-scope
revocation, idempotent, audited via structured log; unlink remains the
documented whole-provider full revocation).
- Typed client regenerated; web connected-accounts card shows the consent
record (date, terms version, scope chips) with per-scope revoke wired
to a server action; en-US/pt-BR strings added.
- Tests: persistence round-trip, callback/link recording, list shape,
revocation (handler/controller/service/repository), header shape, and
web consent-header parser unit tests.
…goal-20261009 # Conflicts: # packages/infrastructure/client/src/generated/.metadata.json
- Handlers test: ResolveAuthorizationScopes mock setups now match the
provider case-insensitively, mirroring the real OAuthService (the
link-preview handler passes the caller's casing through); the previous
exact-match setup returned Moq's empty-array default for 'Discord'.
- Repository round-trip test: expected list contained a stray prose
string ('JSON list must round-trip in order') leaked into the
assertion; replaced with a real third scope token included in the
serialized input so order preservation is genuinely asserted.
- connected-accounts-card: wrap async onClick handlers in void arrows
to satisfy @typescript-eslint/no-misused-promises (2 errors).
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| BestPractice | 7 medium |
🟢 Metrics 146 complexity · 6 duplication
Metric Results Complexity 146 Duplication 6
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
…goal-20261009 # Conflicts: # packages/infrastructure/client/src/generated/.metadata.json
After merging develop (billing webhook + compliance endpoints landed while this branch was in review), the OpenAPI capture was re-run locally against the merged tree (Release publish + swagger capture + pnpm generate --force). The generated .gen.ts outputs are byte-identical to the merge result; only the capture hash/timestamp in .metadata.json changed.
The connected-accounts-card async onClick handlers are now wrapped in void arrows, so the file no longer triggers the rule and ESLint's unused- suppression check (pass-on-unpruned-suppressions off) fails the lint gate.
…goal-20261009 # Conflicts: # packages/infrastructure/client/src/generated/.metadata.json
Develop moved again during CI (#758 remember-me regenerated the surface); re-ran the local Release publish + swagger capture + pnpm generate --force against the merged tree. Only the capture hash and the remember-me types from develop's side carry over.
tolstenko
pushed a commit
that referenced
this pull request
Oct 10, 2026
…pes-20261010 feat(auth): fine-grained OAuth scope grants and consent records (#250)
mathrmartins
added a commit
that referenced
this pull request
Oct 11, 2026
…pes-20261010 feat(auth): fine-grained OAuth scope grants and consent records (#250)
mathrmartins
added a commit
that referenced
this pull request
Oct 11, 2026
…pes-20261010 feat(auth): fine-grained OAuth scope grants and consent records (#250)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #250
(Supersedes #760/#767 — identical commits; GitHub was not delivering pull_request events on the previous branch name, so this PR comes from a renamed branch.)
What
Records and manages fine-grained OAuth scope consent per external login link:
ExternalLogingainsGrantedScopes(JSON array, single-sourced viaExternalLoginGrants),ConsentedAt,ConsentVersion(OAuthConsentVersions.Current = 1). Additive migration20261009184414_AddExternalLoginScopeConsent(no child table needed — the link row is the consent record, the cleaner EF shape for the existing model).OAuthService.ResolveAuthorizationScopessingle-sources the exact scope list authorization URLs embed (defaults per provider, configured scopes override, Microsoft unions required OIDC scopes). Link handlers (Google/Discord), the GIS sign-in path, and every OAuth sign-in auto-link path persist it with a consent stamp; unchanged re-authorizations preserve the first-consent stamp, changed scope sets re-record consent.HEAD /v1/auth/external-loginsnow also emitsX-Granted-Scopes: provider=iso-consent-timestamp|consent-version|url-encoded-scopes. NewGET /auth/external-logins/{provider}/link-preview(authorization-time consent screen data). Typed client regenerated; web connected-accounts card shows consent date/terms version/scope chips (en-US/pt-BR strings, parity tests green).POST /auth/external-logins/{provider}/scopes:revoke— per-scope, idempotent, keeps the first-consent stamp, audited via structured log. Whole-providerDELETE /auth/external-logins/{provider}is documented as the full revocation (endpoint description + UI copy).CI repair commit (vs #760's first run)
ResolveAuthorizationScopesmock setups now match provider case-insensitively (link-preview passes the caller's casing; exact-match setup returned Moq's empty-array default for "Discord").@typescript-eslint/no-misused-promises, 2 errors).Tests
GameGuild.Identity.Authentication.UnitTests: +82 tests across controller (22), handlers (29), repository (13), service (18). First CI run: 2630/2632 passed — the 2 failures were the test defects fixed above (production code unchanged).external-login-consent.test.ts7/7 + locale-parity suite green locally; full web suite had zero failures across all executed files.Note on Codacy Static Code Analysis: standing external analysis (non-required) that also failed on previously merged PRs #743/#750 — documented per #740 precedent.