Skip to content

[spring-boot]: generate PreAuthorize from OpenAPI security scopes#24380

Open
JFCote wants to merge 5 commits into
masterfrom
features/add-pre-authorize-in-controller
Open

[spring-boot]: generate PreAuthorize from OpenAPI security scopes#24380
JFCote wants to merge 5 commits into
masterfrom
features/add-pre-authorize-in-controller

Conversation

@JFCote

@JFCote JFCote commented Jul 21, 2026

Copy link
Copy Markdown
Member

Add opt-in Spring Boot support to translate OAuth2/OIDC security requirements
into @PreAuthorize expressions, preserving OpenAPI AND/OR semantics.

@cachescrubber (2022/02) @welshm (2022/02) @MelleD (2022/02) @atextor (2022/02) @manedev79 (2022/02) @javisst (2022/02) @borsch (2022/02) @banlevente (2022/02) @Zomzog (2022/09) @martin-mfg (2023/08) @KannaKim (2026/07)

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Summary by cubic

Adds opt-in generation of Spring Security @PreAuthorize from OpenAPI OAuth2/OIDC scopes for Spring Boot servers. Preserves OpenAPI AND/OR semantics and enables method security with a safe default when enabled.

  • New Features
    • Option: useSpringSecurityPreAuthorize (Spring Boot only; validated).
    • Builds @PreAuthorize with hasAuthority() per scope; OR across requirements, AND within an entry; empty scopes → isAuthenticated(); handles quote escaping in scope names.
    • Configurable authority prefix via springSecurityAuthorityPrefix (default SCOPE_).
    • Uses operation-level security, falling back to top-level security when missing.
    • Auto-adds @EnableMethodSecurity, @PreAuthorize imports, and a minimal SecurityFilterChain bean that permits all by default; adds spring-boot-starter-security to the generated pom.
    • Docs updated, tests added, plus a sample at samples/server/others/springboot-pre-authorize and config bin/configs/spring-boot-pre-authorize.yaml.

Written for commit fd9d7b1. Summary will update on new commits.

Review in cubic

JFCote added 2 commits July 21, 2026 10:57
Add opt-in Spring Boot support to translate OAuth2/OIDC security requirements
into @PreAuthorize expressions, preserving OpenAPI AND/OR semantics.
Also:
enable method security with @EnableMethodSecurity
add Spring Security dependency when enabled
support configurable authority prefix (SCOPE_ by default)
add documentation, tests, and a generated sample

@cubic-dev-ai cubic-dev-ai Bot 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.

3 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="samples/server/others/springboot-pre-authorize/README.md">

<violation number="1" location="samples/server/others/springboot-pre-authorize/README.md:8">
P3: Use "an OpenAPI-enabled" instead of "a OpenAPI-enabled server" for correct grammar before a vowel sound.</violation>
</file>

<file name="modules/openapi-generator/src/main/resources/JavaSpring/api.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/JavaSpring/api.mustache:279">
P2: OpenAPI scope names containing Java/SpEL string delimiters generate uncompilable or altered `@PreAuthorize` expressions because this interpolation bypasses Java-string escaping. Escape the generated expression for a Java annotation literal before rendering it.</violation>
</file>

<file name="modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java">

<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java:4079">
P1: The test expects generated file `ApiApi.java` but the OpenAPI spec uses the tag `Overview` which generates `OverviewApi.java`. Verify the expected file name matches the tag-based naming convention or the test will fail with a NullPointerException.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Map<String, File> files = generator.opts(input).generate().stream()
.collect(Collectors.toMap(File::getName, Function.identity()));

JavaFileAssert.assertThat(files.get("ApiApi.java"))

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.

P1: The test expects generated file ApiApi.java but the OpenAPI spec uses the tag Overview which generates OverviewApi.java. Verify the expected file name matches the tag-based naming convention or the test will fail with a NullPointerException.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java, line 4079:

<comment>The test expects generated file `ApiApi.java` but the OpenAPI spec uses the tag `Overview` which generates `OverviewApi.java`. Verify the expected file name matches the tag-based naming convention or the test will fail with a NullPointerException.</comment>

<file context>
@@ -4053,6 +4053,76 @@ public void testHasOperationExtraAnnotation_issue12219_array() throws IOExceptio
+        Map<String, File> files = generator.opts(input).generate().stream()
+                .collect(Collectors.toMap(File::getName, Function.identity()));
+
+        JavaFileAssert.assertThat(files.get("ApiApi.java"))
+                .assertMethod("getOverview")
+                .assertMethodAnnotations()
</file context>

{{{.}}}
{{/vendorExtensions.x-operation-extra-annotation}}
{{#vendorExtensions.x-spring-security-pre-authorize}}
@PreAuthorize("{{{.}}}")

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.

P2: OpenAPI scope names containing Java/SpEL string delimiters generate uncompilable or altered @PreAuthorize expressions because this interpolation bypasses Java-string escaping. Escape the generated expression for a Java annotation literal before rendering it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/JavaSpring/api.mustache, line 279:

<comment>OpenAPI scope names containing Java/SpEL string delimiters generate uncompilable or altered `@PreAuthorize` expressions because this interpolation bypasses Java-string escaping. Escape the generated expression for a Java annotation literal before rendering it.</comment>

<file context>
@@ -272,6 +275,9 @@ public interface {{classname}} {
     {{{.}}}
     {{/vendorExtensions.x-operation-extra-annotation}}
+    {{#vendorExtensions.x-spring-security-pre-authorize}}
+    @PreAuthorize("{{{.}}}")
+    {{/vendorExtensions.x-spring-security-pre-authorize}}
     {{#vendorExtensions.x-sse}}
</file context>

## Overview
This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project.
By using the [OpenAPI-Spec](https://openapis.org), you can easily generate a server stub.
This is an example of building a OpenAPI-enabled server in Java using the SpringBoot framework.

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.

P3: Use "an OpenAPI-enabled" instead of "a OpenAPI-enabled server" for correct grammar before a vowel sound.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/others/springboot-pre-authorize/README.md, line 8:

<comment>Use "an OpenAPI-enabled" instead of "a OpenAPI-enabled server" for correct grammar before a vowel sound.</comment>

<file context>
@@ -0,0 +1,12 @@
+## Overview
+This server was generated by the [OpenAPI Generator](https://openapi-generator.tech) project.
+By using the [OpenAPI-Spec](https://openapis.org), you can easily generate a server stub.
+This is an example of building a OpenAPI-enabled server in Java using the SpringBoot framework.
+
+
</file context>

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 11 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread samples/server/others/springboot-pre-authorize/pom.xml Outdated

@cubic-dev-ai cubic-dev-ai Bot 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.

2 issues found across 7 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/main/resources/JavaSpring/libraries/spring-boot/openapi2SpringBoot.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/JavaSpring/libraries/spring-boot/openapi2SpringBoot.mustache:36">
P1: Reactive generated servers fail to initialize when this option is enabled because WebFlux does not provide the servlet `HttpSecurity` builder required by this bean. Render a `ServerHttpSecurity`/`SecurityWebFilterChain` configuration for `reactive`, or reject this option combination.</violation>
</file>

<file name="samples/server/others/springboot-pre-authorize/src/main/java/org/openapitools/OpenApiGeneratorApplication.java">

<violation number="1" location="samples/server/others/springboot-pre-authorize/src/main/java/org/openapitools/OpenApiGeneratorApplication.java:28">
P2: A separately declared `SecurityFilterChain` can fail to replace this fallback because `@ConditionalOnMissingBean` only sees definitions processed so far in this non-auto-configuration class. When this chain is registered first, its universal matcher can take precedence over the application's OAuth/JWT chain; place the fallback in ordered auto-configuration or omit it from the sample application.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

{{#useSpringSecurityPreAuthorize}}
@Bean
@ConditionalOnMissingBean(SecurityFilterChain.class)
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

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.

P1: Reactive generated servers fail to initialize when this option is enabled because WebFlux does not provide the servlet HttpSecurity builder required by this bean. Render a ServerHttpSecurity/SecurityWebFilterChain configuration for reactive, or reject this option combination.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/JavaSpring/libraries/spring-boot/openapi2SpringBoot.mustache, line 36:

<comment>Reactive generated servers fail to initialize when this option is enabled because WebFlux does not provide the servlet `HttpSecurity` builder required by this bean. Render a `ServerHttpSecurity`/`SecurityWebFilterChain` configuration for `reactive`, or reject this option combination.</comment>

<file context>
@@ -26,6 +30,17 @@ import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGe
+{{#useSpringSecurityPreAuthorize}}
+    @Bean
+    @ConditionalOnMissingBean(SecurityFilterChain.class)
+    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+        return http
+            .csrf(AbstractHttpConfigurer::disable)
</file context>

public class OpenApiGeneratorApplication {

@Bean
@ConditionalOnMissingBean(SecurityFilterChain.class)

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.

P2: A separately declared SecurityFilterChain can fail to replace this fallback because @ConditionalOnMissingBean only sees definitions processed so far in this non-auto-configuration class. When this chain is registered first, its universal matcher can take precedence over the application's OAuth/JWT chain; place the fallback in ordered auto-configuration or omit it from the sample application.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/others/springboot-pre-authorize/src/main/java/org/openapitools/OpenApiGeneratorApplication.java, line 28:

<comment>A separately declared `SecurityFilterChain` can fail to replace this fallback because `@ConditionalOnMissingBean` only sees definitions processed so far in this non-auto-configuration class. When this chain is registered first, its universal matcher can take precedence over the application's OAuth/JWT chain; place the fallback in ordered auto-configuration or omit it from the sample application.</comment>

<file context>
@@ -20,6 +24,15 @@
 public class OpenApiGeneratorApplication {
 
+    @Bean
+    @ConditionalOnMissingBean(SecurityFilterChain.class)
+    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+        return http
</file context>

@JFCote

JFCote commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

Let me know if there is anything else to fix and I will take care of it.

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