[TT-17172] OAuth2 security scheme: foundation container#8198
Conversation
|
This PR introduces the foundational container for a new-style OAuth2 security scheme. It allows operators to declare the scheme in an API definition, enabling the gateway to parse, validate, and round-trip the configuration. This initial implementation is a non-functional skeleton; the logic for token validation, scope checks, and other OAuth2 flows will be added in subsequent work. Files Changed AnalysisThe core logic is introduced in two new files, Architecture & Impact Assessment
OAS Generation Flow for Security Schemesgraph TD
A[API Load] --> B(fillSecurity);
B --> C(fillBasic);
B --> D(fillOAuth);
B --> E(fillExternalOAuth);
B --> F(fillOAuth2);
F --> G{Scheme Enabled?};
G -- Yes --> H(Add to OAS Components);
G -- No --> I(Do not advertise in OAS);
style F fill:#cde4ff,stroke:#6495ED,stroke-width:2px
Scope Discovery & Context ExpansionThe changes in this PR are confined to the API definition structure and the gateway's configuration loading process. There is no immediate impact on runtime request processing or traffic management, as the introduced scheme is a non-functional container. The primary risk, as noted by the author, is the potential for drift between the four duplicated schema definitions, which must be kept in sync manually. A key architectural decision, confirmed by the test This work is the first step in a larger initiative to implement a comprehensive, new-style OAuth2 security provider. Subsequent PRs will build upon this foundation by adding configuration and logic for features like token introspection, scope validation, and token exchange. These future changes will populate the Metadata
Powered by Visor from Probelabs Last updated: 2026-05-14T08:09:50.551Z | Triggered by: pr_updated | Commit: f126d68 💡 TIP: You can chat with Visor using |
Security Issues (2)
Architecture Issues (2)
✅ Performance Check PassedNo performance issues found – changes LGTM. Security Issues (2)
Quality Issues (3)
|
baf9ceb to
7f92ebd
Compare
Adds the new-style oauth2 security scheme as an empty container that
operators can declare and round-trip through the gateway. The scheme
exposes a master `Enabled` toggle and inherits the standard
`AuthSources` contract; subsequent feature work plugs additional
sub-blocks into this container.
Apidef
- OAuth2 struct with Enabled + AuthSources, stored under
x-tyk-api-gateway.server.authentication.securitySchemes[name].
- HasContent / IsEmpty predicates.
- fillOAuth2 / fillOAuth2OASScheme materialise pre-typed *OAuth2
entries into the public OAS document with a typeOAuth2 entry under
Components.SecuritySchemes.
- GetTykOAuth2Config / IsOAuth2Scheme helpers.
- Schema deltas in apidef/{oas, oas-strict, mcp, streams}/schema/
x-tyk-api-gateway.json: add the X-Tyk-OAuth2 definition (enabled +
AuthSource refs) and reference it from the securitySchemes
pattern-properties anyOf list.
- security.go: add *OAuth2 to isProprietarySchemeType and call
s.fillOAuth2() from fillSecurity after the existing scheme fillers.
Gateway
- APISpec.GetOAuth2Config returns one configured oauth2 scheme on an
OAS API; duplicates are accepted (map-iteration first match),
matching the behaviour of every other auth scheme on this map
(JWT, Token, HMAC, Basic, OIDC, ExternalOAuth).
Tests
- apidef/oas: HasContent / IsEmpty for nil, zero, and enabled
receivers; fill adds OAS Components entry for enabled schemes;
fill skips disabled schemes from OAS Components; JSON round-trip
preserves enabled; IsOAuth2Scheme lookup.
- gateway: GetOAuth2Config returns one of the configured schemes
when duplicates are present and APISpec.Validate accepts the
doc at load time.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
da95b9b to
f126d68
Compare
|
## Summary Adds the OAS-native OAuth 2.0 `scopeCheck` sub-block on the new `oauth2` security scheme and the gateway middleware that enforces it. Required scopes live in the **OAS root `security:` array** — standard OpenAPI Security Requirement Objects, OR-of-AND across entries. The `scopeCheck` block on the Tyk extension carries only the token-side knobs: which JWT claims to read scopes from, how to split string-form values, and which scope-source mode is active. Validation, scope merging across claims, and the RFC 6750 §3 `Bearer SP 1#auth-param` failure challenge all live here. The scheme is name-agnostic — operators can name the OAS `securitySchemes` entry anything (`oauth2`, `prctOauth`, `corpOAuth`, …); enforcement uses whatever name the document declares. ## Story - JIRA: https://tyktech.atlassian.net/browse/TT-17173 ## Stacked on This PR is stacked on TT-17172 — #8198. Review/merge that first; once it merges this can be retargeted to `master`. ## Companion PRs These three ship together — please block until all three are green: - `tyk`: this PR - `tyk-analytics`: TykTechnologies/tyk-analytics#5629 - `tyk-analytics-ui`: TykTechnologies/tyk-analytics-ui#4370 ## Behaviour ### Apidef (`apidef/oas/`) - `OAuth2ScopeCheck`: `Enabled`, `ClaimNames []string`, `Separator string`, `ScopeSource string`. There is no `Scopes` field — scope policy lives in OAS root `security:`. - `ScopeSource` constants: `operation`, `global`, `union` (default). - Map-probe disambiguator (`asOAuth2Scheme` + `mapHasOAuth2SubBlock`) tells the OAS-native `OAuth2` scheme apart from legacy `*OAuth` / `*ExternalOAuth` schemes after JSON round-trip — recognised by presence of an oauth2 sub-block key. - `SecurityRequirementScopes [][]map[string][]string` sibling field on `apidef.APIDefinition` preserves per-scheme scope arrays across the extract/fill round-trip (omitempty; forward-compatible). - `extractSecurityTo` single-alternative branch: populates `SecurityRequirements` with every scheme in the requirement (including empty-scope ones like `jwtAuth: []`) so multi-scheme single-AND security policies (JWT + OAuth2 in one entry) survive round-trip without silently dropping the JWT scheme. - Validator rejects an unknown `scopeSource` at API load with a clear error. - Strict + non-strict OAS schemas declare `X-Tyk-OAuth2-ScopeCheck` with the four token-side fields. ### Gateway (`gateway/mw_oauth2.go`) - `OAuth2Middleware` enforces scope check when `oauth2.enabled` and `scopeCheck.enabled` are both true. - `rootSecurityAlternatives(security, schemeName, scopeCheck)` reads root `security:` and returns the OR-of-AND list of alternatives drawn from entries that reference the configured scheme. Declared order is preserved end-to-end so the operator sees their authored form on the failure challenge. - Token's scope set is the **merged union** across every claim in `ClaimNames` (default `["scope", "scp"]`). Each claim value is parsed by `Separator` (default single space), JSON array form, or comma-separated form per RFC 6749 §3.3. - On insufficient scope: 403, RFC 6750 §3 `WWW-Authenticate: Bearer error="insufficient_scope" …` challenge citing the **first** declared alternative only (intentionally — listing every alternative would leak that the API has a service-account path and a user path), JSON body with `error` / `error_description` / `scope`, and an `OAuth2ScopeCheckFailed` audit event carrying the cited alternative + full alternative list. - An entry that lists the scheme with an empty scope list (`security: - oauth2: []`) is treated as "auth required, no specific scope" — vacuously satisfied, short-circuits the OR to pass. ### Wire-protocol constants - `OAuth2ErrInsufficientScope` = `"insufficient_scope"` (RFC 6750 §3.1) - `OAuth2ErrInvalidToken` = `"invalid_token"` (RFC 6750 §3.1) ## Test plan - [x] `go test ./apidef/oas/ ./gateway/ ./internal/oauth2common/` — unit tests cover: nil/empty/operation-suppression, single-AND, OR-across, OR-of-AND, sort+dedup, vacuous-satisfaction, multi-scheme single-alternative round-trip preservation, name-agnostic enforcement (`TestOAuth2Middleware_NameAgnostic`), RFC 6750 §3 challenge header form - [x] Python e2e — runs in the dashboard companion PR - [ ] Postman collection via newman - [ ] Manual smoke ## Risk Failure-challenge form cites only the first declared alternative — deliberate, regression-tested. The strict-schema deltas across four schema files must stay in sync. The map-probe disambiguator's sub-block key list (`oauth2SubBlockKeys`) needs an entry added whenever a new OAuth2 sub-block is introduced, otherwise the typed view is silently dropped on JSON round-trip. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!---TykTechnologies/jira-linter starts here--> ### Ticket Details <details> <summary> <a href="https://tyktech.atlassian.net/browse/TT-17173" title="TT-17173" target="_blank">TT-17173</a> </summary> | | | |---------|----| | Status | Merge | | Summary | OAuth2 scope check — global / API level | Generated at: 2026-05-26 15:20:57 </details> <!---TykTechnologies/jira-linter ends here--> Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>



Summary
Introduces the new-style
oauth2security scheme as an empty container. Operators can declare and round-trip the scheme; the sub-blocks (scope check, protected-resource metadata, token exchange, introspection) plug into this container in follow-up work.Apidef:
OAuth2struct (masterEnabled+ standardAuthSources),HasContent/IsEmpty,fillOAuth2/fillOAuth2OASScheme,GetTykOAuth2Config/IsOAuth2Schemehelpers, schema deltas in 4 files (oas, oas-strict, mcp, streams). Gateway:APISpec.GetOAuth2Configreturns one configured oauth2 scheme on an OAS API.Duplicate
oauth2schemes on the same API are not validated —GetOAuth2Configreturns the first match from map iteration. This matches the behaviour of every other auth scheme on theSecuritySchemesmap (JWT, Token, HMAC, Basic, OIDC, ExternalOAuth); there is no per-scheme uniqueness validator anywhere inapidef/oasfor those schemes either.Story
Companion PRs
GW-only — this work ships to
tykonly. Sub-blocks land in TT-17173 (#8199, stacked on this branch, with companions TykTechnologies/tyk-analytics#5629 and TykTechnologies/tyk-analytics-ui#4370) and beyond.Test plan
go test ./apidef/oas/ ./gateway/clean —HasContent/IsEmpty/ fill round-trip /IsOAuth2Scheme/TestGetOAuth2Config_AcceptsDuplicatesAndReturnsOne(pins that duplicate oauth2 schemes are accepted at load time andGetOAuth2Configreturns one)Risk
Schema deltas in 4 files (oas, oas-strict, mcp, streams) — they mirror each other and must stay in sync; drift is a silent-UI-breakage class of bug. The map-probe disambiguator is intentionally absent at this stage and is introduced when the first sub-block lands.
🤖 Generated with Claude Code
Ticket Details
TT-17172
oauth2security scheme (foundation)Generated at: 2026-05-14 08:07:27