Skip to content

Management API: Override document-level security on AllowAnonymous endpoints#22712

Merged
lauraneto merged 2 commits into
v18/devfrom
v18/bugfix/openapi-anonymous-security-override
May 5, 2026
Merged

Management API: Override document-level security on AllowAnonymous endpoints#22712
lauraneto merged 2 commits into
v18/devfrom
v18/bugfix/openapi-anonymous-security-override

Conversation

@iOvergaard

Copy link
Copy Markdown
Contributor

Summary

On v18/dev, opening the backoffice on a freshly checked-out (uninstalled) project crashes the install screen — the very first request to GET /umbraco/management/api/v1/server/status returns a 500 (OpenIddict trying to resolve UmbracoDbContext with no connection string), and the backoffice fires POST /umbraco/management/api/v1/security/back-office/token before the user has even reached the install form.

Root cause: PR #21058 (switch to Microsoft.AspNetCore.OpenApi) caused the OpenAPI document to declare security: [{ Backoffice-User: [] }] at the document level. By the OpenAPI 3.x spec, that requirement is inherited by every operation that does not explicitly override it with its own security array — including the empty array security: []. BackOfficeSecurityRequirementsTransformer correctly skipped adding a security entry to operations on [AllowAnonymous] actions, but it never inserted the empty-array override, so the generated SDK (sdk.gen.ts) ended up declaring security: [{ scheme: 'bearer', type: 'http' }] on getServerStatus, getServerConfiguration, the install endpoints, etc. That in turn told umbHttpClient's auth callback to call #ensureTokenReady() for those calls, which triggered the early /token refresh.

This branch is v17 (main) is not affected because main's checked-in sdk.gen.ts predates the Microsoft.AspNetCore.OpenApi switch and contains no document-level security default.

Changes

  • BackOfficeSecurityRequirementsTransformer: when an operation's action method (or its declaring type) is [AllowAnonymous], set operation.Security = [] so the operation overrides the document-level Backoffice-User requirement.
  • Regenerated OpenApi.json: 10 anonymous operations now carry "security": [] (/server/status, /server/configuration, /install/settings, /install/setup, /install/validate-database, /manifest/manifest/public, /preview DELETE, /security/forgot-password/verify, /user/invite/create-password, /user/invite/verify).
  • Regenerated sdk.gen.ts: matching security: [...] arrays removed from those 10 operations.

Test plan

Reproduced and verified in a fresh worktree (v18/dev) with empty connection string:

  • Before fix: GET /server/status → 500, POST /security/back-office/token fires before the install screen renders, OpenIddict stack trace in console.
  • After fix: install screen loads cleanly. Network shows only GET /server/status (200), GET /server/configuration (200), GET /manifest/manifest/public (200), GET /install/settings (200). No Authorization header on those calls. No /token request.
  • End-to-end install + login flow still works (filled install form → completed install → logged in → landed on /umbraco/section/content).

Reported by @nielslyngsoe on Slack.

…dpoints

Operations on controllers/actions decorated with [AllowAnonymous] inherit the
document-level Bearer security requirement in OpenAPI 3.x unless they explicitly
declare an empty security array. Without that override, the generated SDK
attaches an Authorization: Bearer header to anonymous endpoints (server/status,
server/configuration, install/*, manifest/manifest/public, etc.), which forces
a /security/back-office/token refresh during the very first page load.

On v18/dev this manifests as a 500 from /server/status during a fresh install:
the Authorization header triggers OpenIddict, which resolves UmbracoDbContext
from DI, which throws because the connection string is empty in the install
state.

The transformer now sets operation.Security = [] on AllowAnonymous endpoints so
they correctly opt out of the document-level security. The committed OpenApi.json
and the regenerated sdk.gen.ts reflect this.
@iOvergaard iOvergaard marked this pull request as ready for review May 5, 2026 11:23
Copilot AI review requested due to automatic review settings May 5, 2026 11:23
@claude

claude Bot commented May 5, 2026

Copy link
Copy Markdown

Claude finished @iOvergaard's task in 4m 50s —— View job


PR Review

Target: origin/v18/dev · Based on commit: dbdf339d · Skipped: 1 file out of 3 total (sdk.gen.ts — auto-generated)

Fixes a v18/dev-only regression where BackOfficeSecurityRequirementsTransformer added a document-level Backoffice-User security requirement but never inserted an empty-array override on [AllowAnonymous] operations, causing the generated SDK to attach a Bearer token to anonymous endpoints (install, server status, etc.) and triggering a fatal OpenIddict error during fresh install.

  • Other changes: 10 anonymous operations in OpenApi.json now explicitly declare "security": [], and the corresponding SDK auth callbacks are removed from sdk.gen.ts.

Important

  • src/Umbraco.Cms.Api.Management/OpenApi/Transformers/BackOfficeSecurityRequirementsTransformer.cs:43: The fix sets operation.Security = [] for anonymous operations, but the two existing unit tests (TransformAsync_Operation_Skips_AllowAnonymous_Methods and TransformAsync_Operation_Skips_AllowAnonymous_Controllers at lines 138–139 and 168–170 of BackOfficeSecurityRequirementsTransformerTests.cs) still assert Assert.IsNull(operation.Security). An empty list is not null — those assertions will fail. Update them to Assert.IsNotNull(operation.Security); Assert.IsEmpty(operation.Security); to validate the new intentional behaviour. (Inline comment posted.)

Request Changes

The core fix is correct and the approach is right. The one Important issue (unit tests asserting null instead of empty list) needs to be resolved to keep the test suite green.

Copilot AI left a comment

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.

Pull request overview

Fixes an issue in the Management API OpenAPI generation where document-level security requirements were implicitly inherited by [AllowAnonymous] operations, causing the generated backoffice SDK to treat anonymous endpoints as authenticated and trigger premature token refresh during install/uninitialized startup.

Changes:

  • Update BackOfficeSecurityRequirementsTransformer to explicitly set operation.Security = [] for [AllowAnonymous] endpoints to override document-level security.
  • Regenerate OpenApi.json so affected anonymous endpoints now include "security": [].
  • Regenerate the backoffice TypeScript SDK (sdk.gen.ts) to remove per-operation bearer security declarations for those anonymous endpoints.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/Umbraco.Cms.Api.Management/OpenApi/Transformers/BackOfficeSecurityRequirementsTransformer.cs Ensures anonymous operations explicitly override document-level security by emitting an empty security array.
src/Umbraco.Cms.Api.Management/OpenApi.json Reflects the override by adding "security": [] to the affected anonymous operations.
src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts Removes bearer security metadata from generated client calls for the affected anonymous endpoints.

The transformer now sets operation.Security = [] (empty list) on
[AllowAnonymous] endpoints to override document-level security, instead
of leaving it null. Update the two affected tests to assert the new
behaviour and rename them to reflect that the transformer overrides
rather than skips security on anonymous operations.

@lauraneto lauraneto left a comment

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.

Looks and tests good!
I updated the failing unit tests with the new behavior.

@lauraneto lauraneto enabled auto-merge (squash) May 5, 2026 15:09
@lauraneto lauraneto merged commit 2c9acb3 into v18/dev May 5, 2026
30 checks passed
@lauraneto lauraneto deleted the v18/bugfix/openapi-anonymous-security-override branch May 5, 2026 15:17
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.

3 participants