Skip to content

Fix bearer-only security builds and bearer scheme name mapping - #74

Merged
davidkallesen merged 4 commits into
mainfrom
fix/security-bearer-without-policies
Sep 24, 2026
Merged

davidkallesen merged 4 commits into
mainfrom
fix/security-bearer-without-policies

Conversation

@davidkallesen

Copy link
Copy Markdown
Contributor

Summary

  • Make specs with a bearer scheme but no roles/policies/scopes compile
  • Stop OPR022 flagging 403 on authenticated operations
  • Map http bearer schemes to the registered "Bearer" auth scheme
  • Cover the unified MinimalApi surface by compilation and at runtime

Changes

🐛 Fixes

  • Always generate AddApiSecurityPolicies() when a scheme exists
  • Register AddAuthorization() when there are no policies to add
  • Prevent startup failure from UseAuthorization() without services
  • Report OPR022 only when an operation has no security requirement
  • Keep OPR022 for operations opting out with "security: []"
  • Align OPR022 descriptor title and docs with the new meaning

✨ Features

  • Map "type: http, scheme: bearer" to the "Bearer" scheme name
  • Add x-authentication-scheme extension to override the mapped name
  • Keep the securityScheme key for apiKey, oauth2 and other types

💥 Breaking Changes

  • Endpoints now require "Bearer" instead of the bearer scheme key

♻️ Refactoring

  • Move Showcase and MultipartDemo hosts to default AddJwtBearer()

🔧 Configuration

  • Reference Atc.Rest.MinimalApi in the source generator test project
  • Hide it from scenarios unless a MinimalApi mode is "Enabled"

✅ Tests

  • Add SecurityBearerOnly scenario to the compilation gate
  • Host generated bearer-only code on Kestrel: 401 and 200 paths
  • Add extractor contract tests for security DI generation
  • Add validator tests for OPR022 on secured and anonymous operations
  • Add scheme name mapping tests, including the extension override
  • Update SecurityStandard baselines for the "Bearer" scheme name

Breaking Changes

  • Bearer endpoints now call AddAuthenticationSchemes("Bearer")
  • Previously they used the securityScheme key, e.g. "bearer_auth"
  • Hosts using AddJwtBearer("") will fail every request
  • Fix: switch to the default AddJwtBearer(...) registration
  • Or: add x-authentication-scheme: to the securityScheme

David Kallesen added 4 commits September 24, 2026 08:18
…heme exists

A spec that applied a bearer scheme without any role, policy or scope did
not compile: the unified Add{Project}Api() referenced the Generated.Security
namespace and AddApiSecurityPolicies() whenever a scheme existed, while the
security DI extractor only emitted them when there was a policy to register.

The extractor now follows the same condition as its caller. With no policy
the method just calls services.AddAuthorization(), which the generated
UseAuthorization() needs anyway - skipping the call instead would have
turned the compile error into a startup failure for hosts that do not
register authorization themselves.
An authenticated operation may return 403 for application-level reasons,
such as "not a known user" or "not your resource", without any role,
policy or scope in the spec. OPR022 flagged every such operation, which
broke builds using TreatWarningsAsErrors on perfectly standard specs.

The rule now fires only when the operation has no effective security
requirement: none declared, or opted out with "security: []".
…ion scheme

Endpoints passed the securityScheme key to AddAuthenticationSchemes(), but
ASP.NET Core only authenticates against a registered scheme, and
AddJwtBearer() / AddMicrosoftIdentityWebApi() register "Bearer". A spec
using the conventional key "BearerAuth" therefore built green and then
failed every request with "No authentication handler is registered".

A "type: http, scheme: bearer" securityScheme now maps to "Bearer". The new
x-authentication-scheme extension on a securityScheme names any other
registered scheme, and every other scheme type keeps its key.

Hosts that registered AddJwtBearer("<securityScheme key>") to match the old
behaviour must switch to the default AddJwtBearer() or add
x-authentication-scheme to the spec. The Showcase and MultipartDemo hosts
did exactly that and are moved to the default here.
…erenced

No scenario ever produced the unified Add{Project}Api()/Map{Project}Api()
surface, because the test host never referenced Atc.Rest.MinimalApi - which
is how the missing AddApiSecurityPolicies() went unnoticed.

The package is now referenced, but hidden from a scenario unless its Server
marker sets a MinimalApi mode to "Enabled", so the "Auto" scenarios keep
their output. The new SecurityBearerOnly scenario opts in and goes through
the compilation gate, and runtime tests host its generated code on Kestrel:
401 without a token, 200 with one and no role.
@davidkallesen
davidkallesen merged commit 519de77 into main Sep 24, 2026
7 checks passed
@davidkallesen
davidkallesen deleted the fix/security-bearer-without-policies branch September 24, 2026 06:39
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