or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

aot-native-support.mdauthentication-core.mdauthentication-events.mdauthentication-management.mdauthentication-tokens.mdauthorities.mdauthorization.mdcompromised-password.mdconcurrent-async.mddao-authentication.mdexpression-access-control.mdindex.mdjaas-authentication.mdjackson-serialization.mdmethod-security.mdobservation-metrics.mdone-time-tokens.mdprovisioning.mdsecurity-context.mdsession-management.mduser-details.md
tile.json

aot-native-support.mddocs/

AOT and GraalVM Native Image Support

Overview

Spring Security 6.0+ provides comprehensive support for Ahead-of-Time (AOT) compilation and GraalVM native image generation. This enables Spring Security applications to compile to native executables with fast startup times and reduced memory footprint.

Key Information for Agents

Core Capabilities:

  • Runtime hints registration via SecurityHintsRegistrar interface
  • Automatic hint discovery for core security types
  • Method security hints via PrePostAuthorizeHintsRegistrar and AuthorizeReturnObjectHintsRegistrar
  • Expression bean hints via PrePostAuthorizeExpressionBeanHintsRegistrar
  • Core hints: CoreSecurityRuntimeHints (package-private, auto-registered)
  • Custom hint registration for application-specific types

Key Interfaces and Classes:

  • SecurityHintsRegistrar - Interface: registerHints(RuntimeHints, ConfigurableListableBeanFactory)
  • AuthorizeReturnObjectHintsRegistrar - Registers proxy hints for @AuthorizeReturnObject
  • AuthorizeReturnObjectCoreHintsRegistrar - Auto-discovers @AuthorizeReturnObject methods
  • PrePostAuthorizeHintsRegistrar - Registers hints for @PreAuthorize / @PostAuthorize
  • PrePostAuthorizeExpressionBeanHintsRegistrar - Registers hints for beans used in expressions
  • RuntimeHints - Spring AOT hints API (reflection, resources, proxies, serialization)

Default Behaviors:

  • Core hints automatically registered by Spring Security (no configuration needed)
  • Method security hints require explicit registration (via SecurityHintsRegistrar beans)
  • Expression bean hints require explicit registration (list bean classes)
  • Authorization proxy hints require AuthorizationProxyFactory (auto-discovery available)

Threading Model:

  • Hints registered at build time (AOT processing)
  • No runtime threading concerns

Lifecycle:

  • Hints registered during AOT processing (before native compilation)
  • Runtime hints used during native image generation
  • No runtime registration (all hints must be known at build time)

Exceptions:

  • Build-time errors: Missing hints cause native image build failures
  • Runtime errors: ClassNotFoundException, NoSuchMethodException if hints missing

Edge Cases:

  • Custom authentication types: Must register reflection hints explicitly
  • Custom user details: Must register reflection hints
  • Expression beans: Must register via PrePostAuthorizeExpressionBeanHintsRegistrar
  • Authorization proxies: Auto-discovery available via AuthorizeReturnObjectCoreHintsRegistrar
  • Resources: Register message bundles, SQL schemas, config files
  • Proxies: Register JDK proxy interfaces for AOP
  • Serialization: Register serializable types (Authentication, SecurityContext, etc.)

Core Components

Security Hints Registrar

SecurityHintsRegistrar

Base interface for registering Spring Security runtime hints for AOT compilation.

public interface SecurityHintsRegistrar { .api }

Description: Strategy interface for registering runtime hints required for native image compilation.

Methods:

void registerHints(RuntimeHints hints,
                   ConfigurableListableBeanFactory beanFactory) { .api }
  • Registers runtime hints for reflection, resources, proxies, and serialization
  • Parameters:
    • hints - RuntimeHints to register hints into
    • beanFactory - BeanFactory for scanning application beans

Package: org.springframework.security.aot.hint

Since: 6.4

Core Hints Registrars

CoreSecurityRuntimeHints

Registers core Spring Security runtime hints.

final class CoreSecurityRuntimeHints implements RuntimeHintsRegistrar { .api }

Description: Registers hints for core Spring Security classes required at runtime.

Registered Hints:

Resource Hints:

  • org.springframework.security.messages - Message bundles
  • JDBC schema DDL locations
  • Security configuration files

Reflection Hints:

  • All AuthenticationException subclasses
  • Security expression classes
  • Authentication token types
  • Core security interfaces

Package: org.springframework.security.aot.hint (package-private)

Since: 6.0

Registered Classes:

// Authentication exceptions
- BadCredentialsException
- UsernameNotFoundException
- AccountExpiredException
- CredentialsExpiredException
- DisabledException
- LockedException
- InsufficientAuthenticationException
- AuthenticationServiceException
- AuthenticationCredentialsNotFoundException
- ProviderNotFoundException

// Core types
- Authentication
- GrantedAuthority
- UserDetails
- SecurityContext

// Expression classes
- SecurityExpressionRoot
- MethodSecurityExpressionOperations

OneTimeTokenRuntimeHints

Registers hints for one-time token functionality.

final class OneTimeTokenRuntimeHints implements RuntimeHintsRegistrar { .api }

Description: Registers resource hints for OTT JDBC schema.

Registered Resources:

  • org/springframework/security/core/ott/jdbc/one-time-tokens-schema.sql

Package: org.springframework.security.aot.hint (package-private)

Since: 6.4

Authorization Proxy Hints

AuthorizeReturnObjectHintsRegistrar

Registers hints for @AuthorizeReturnObject proxy generation.

public final class AuthorizeReturnObjectHintsRegistrar
    implements SecurityHintsRegistrar { .api }

Description: Scans for types requiring authorization proxy generation and registers proxy hints.

Constructors:

public AuthorizeReturnObjectHintsRegistrar(
    AuthorizationProxyFactory proxyFactory,
    Class<?>... targetClasses) { .api }
  • Registers hints for specific target classes
  • Parameters:
    • proxyFactory - Factory for creating authorization proxies
    • targetClasses - Classes to register proxy hints for
public AuthorizeReturnObjectHintsRegistrar(
    AuthorizationProxyFactory proxyFactory,
    List<Class<?>> targetClasses) { .api }
  • List-based constructor variant

Package: org.springframework.security.aot.hint

Since: 6.4

Example:

@Configuration
public class NativeSecurityConfig {

    @Bean
    public SecurityHintsRegistrar authorizeReturnObjectHints(
            AuthorizationProxyFactory proxyFactory) {
        return new AuthorizeReturnObjectHintsRegistrar(
            proxyFactory,
            Document.class,
            Report.class,
            UserProfile.class
        );
    }
}

AuthorizeReturnObjectCoreHintsRegistrar

Automatically discovers beans with @AuthorizeReturnObject methods and registers hints.

public final class AuthorizeReturnObjectCoreHintsRegistrar
    implements SecurityHintsRegistrar { .api }

Description: Scans application beans for @AuthorizeReturnObject usage and registers proxy hints automatically.

Constructor:

public AuthorizeReturnObjectCoreHintsRegistrar(
    AuthorizationProxyFactory proxyFactory) { .api }

Package: org.springframework.security.aot.hint

Since: 6.4

Example:

@Configuration
public class AutoScanSecurityConfig {

    @Bean
    public SecurityHintsRegistrar autoScanProxyHints(
            AuthorizationProxyFactory proxyFactory) {
        // Automatically discovers all @AuthorizeReturnObject methods
        return new AuthorizeReturnObjectCoreHintsRegistrar(proxyFactory);
    }
}

// Application code - automatically discovered
@Service
public class DocumentService {

    @AuthorizeReturnObject
    public Document getDocument(Long id) {
        return documentRepository.findById(id);
    }
}

Method Security Hints

PrePostAuthorizeHintsRegistrar

Registers hints for @PreAuthorize and @PostAuthorize annotations.

public final class PrePostAuthorizeHintsRegistrar
    implements SecurityHintsRegistrar { .api }

Description: Scans for @PreAuthorize/@PostAuthorize annotations and registers reflection hints for method security.

Package: org.springframework.security.aot.hint

Since: 6.4

Registered Hints:

  • Reflection hints for secured methods
  • Proxy generation hints for AOP
  • Expression evaluation hints

Example:

@Bean
public SecurityHintsRegistrar prePostAuthorizeHints() {
    return new PrePostAuthorizeHintsRegistrar();
}

PrePostAuthorizeExpressionBeanHintsRegistrar

Registers hints for beans referenced in security expressions.

public final class PrePostAuthorizeExpressionBeanHintsRegistrar
    implements SecurityHintsRegistrar { .api }

Description: Registers reflection hints for beans used in @PreAuthorize/@PostAuthorize expressions.

Constructors:

public PrePostAuthorizeExpressionBeanHintsRegistrar(
    Class<?>... beanClasses) { .api }
  • Registers hints for specific bean classes
  • Parameters: beanClasses - Classes used in security expressions
public PrePostAuthorizeExpressionBeanHintsRegistrar(
    List<Class<?>> beanClasses) { .api }
  • List-based constructor variant

Package: org.springframework.security.aot.hint

Since: 6.4

Example:

// Security expression using custom bean
@PreAuthorize("@permissionEvaluator.hasPermission(#document)")
public void updateDocument(Document document) { }

// Register hints for expression beans
@Bean
public SecurityHintsRegistrar expressionBeanHints() {
    return new PrePostAuthorizeExpressionBeanHintsRegistrar(
        CustomPermissionEvaluator.class,
        DocumentValidator.class
    );
}

@Component("permissionEvaluator")
public class CustomPermissionEvaluator {
    public boolean hasPermission(Document document) {
        // Permission logic
        return true;
    }
}

Configuration

Basic Native Configuration

Enable native image support in Spring Boot application:

@SpringBootApplication
public class NativeSecurityApplication {

    public static void main(String[] args) {
        SpringApplication.run(NativeSecurityApplication.class, args);
    }

    // Spring Security automatically registers core hints
}

Maven Configuration (pom.xml):

<build>
    <plugins>
        <plugin>
            <groupId>org.graalvm.buildtools</groupId>
            <artifactId>native-maven-plugin</artifactId>
            <configuration>
                <imageName>${project.artifactId}</imageName>
                <mainClass>${project.groupId}.NativeSecurityApplication</mainClass>
                <buildArgs>
                    <buildArg>--no-fallback</buildArg>
                    <buildArg>-H:+ReportExceptionStackTraces</buildArg>
                </buildArgs>
            </configuration>
        </plugin>
    </plugins>
</build>

Gradle Configuration (build.gradle):

plugins {
    id 'org.graalvm.buildtools.native' version '0.9.28'
}

graalvmNative {
    binaries {
        main {
            imageName = project.name
            mainClass = 'com.example.NativeSecurityApplication'
            buildArgs.add('--no-fallback')
            buildArgs.add('-H:+ReportExceptionStackTraces')
        }
    }
}

Custom Hints Registration

Register custom security hints:

@Configuration
public class CustomSecurityHintsConfig {

    @Bean
    public RuntimeHintsRegistrar customSecurityHints() {
        return (hints, classLoader) -> {
            // Register custom authentication classes
            hints.reflection()
                .registerType(CustomAuthenticationToken.class,
                    MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS,
                    MemberCategory.INVOKE_PUBLIC_METHODS,
                    MemberCategory.DECLARED_FIELDS);

            // Register custom user details
            hints.reflection()
                .registerType(CustomUserDetails.class,
                    MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS,
                    MemberCategory.INVOKE_PUBLIC_METHODS);

            // Register custom exceptions
            hints.reflection()
                .registerType(CustomAuthenticationException.class,
                    MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);

            // Register resources
            hints.resources()
                .registerPattern("custom-security-config.properties");

            // Register proxies
            hints.proxies()
                .registerJdkProxy(CustomAuthenticationProvider.class);

            // Register serialization
            hints.serialization()
                .registerType(CustomAuthenticationToken.class);
        };
    }
}

Method Security Hints

Configure hints for method security:

@Configuration
@EnableMethodSecurity
public class MethodSecurityNativeConfig {

    @Bean
    public SecurityHintsRegistrar methodSecurityHints(
            AuthorizationProxyFactory proxyFactory) {

        // Combine multiple registrars
        return (hints, beanFactory) -> {
            // Register @PreAuthorize/@PostAuthorize hints
            PrePostAuthorizeHintsRegistrar prePostRegistrar =
                new PrePostAuthorizeHintsRegistrar();
            prePostRegistrar.registerHints(hints, beanFactory);

            // Register expression bean hints
            PrePostAuthorizeExpressionBeanHintsRegistrar expressionRegistrar =
                new PrePostAuthorizeExpressionBeanHintsRegistrar(
                    PermissionService.class,
                    ValidationService.class
                );
            expressionRegistrar.registerHints(hints, beanFactory);

            // Register authorization proxy hints
            AuthorizeReturnObjectCoreHintsRegistrar proxyRegistrar =
                new AuthorizeReturnObjectCoreHintsRegistrar(proxyFactory);
            proxyRegistrar.registerHints(hints, beanFactory);
        };
    }
}

Complete Native Configuration Example

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class CompleteNativeSecurityConfig {

    @Bean
    public RuntimeHintsRegistrar completeSecurityHints(
            AuthorizationProxyFactory proxyFactory) {
        return (hints, classLoader) -> {
            // 1. Core authentication types
            registerAuthenticationTypes(hints);

            // 2. Custom user details
            registerUserDetailsTypes(hints);

            // 3. Security expressions
            registerExpressionTypes(hints);

            // 4. Resources
            registerResources(hints);

            // 5. Proxies
            registerProxies(hints);

            // 6. Serialization
            registerSerialization(hints);
        };
    }

    private void registerAuthenticationTypes(RuntimeHints hints) {
        hints.reflection()
            .registerType(CustomAuthenticationToken.class,
                builder -> builder
                    .withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)
                    .withMembers(MemberCategory.INVOKE_PUBLIC_METHODS)
                    .withMembers(MemberCategory.DECLARED_FIELDS)
            );
    }

    private void registerUserDetailsTypes(RuntimeHints hints) {
        hints.reflection()
            .registerType(CustomUserDetails.class,
                builder -> builder
                    .withMembers(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)
                    .withMembers(MemberCategory.INVOKE_PUBLIC_METHODS)
            );
    }

    private void registerExpressionTypes(RuntimeHints hints) {
        hints.reflection()
            .registerType(CustomSecurityExpressionRoot.class,
                builder -> builder
                    .withMembers(MemberCategory.INVOKE_PUBLIC_METHODS)
            );
    }

    private void registerResources(RuntimeHints hints) {
        hints.resources()
            .registerPattern("security/*.properties")
            .registerPattern("security/*.xml");
    }

    private void registerProxies(RuntimeHints hints) {
        hints.proxies()
            .registerJdkProxy(AuthenticationProvider.class)
            .registerJdkProxy(UserDetailsService.class);
    }

    private void registerSerialization(RuntimeHints hints) {
        hints.serialization()
            .registerType(CustomAuthenticationToken.class)
            .registerType(CustomUserDetails.class);
    }

    @Bean
    public SecurityHintsRegistrar authorizationProxyHints(
            AuthorizationProxyFactory proxyFactory) {
        return new AuthorizeReturnObjectCoreHintsRegistrar(proxyFactory);
    }
}

Testing Native Image

Native Test Support

Test native image compilation:

@SpringBootTest
@EnabledInNativeImage
class NativeSecurityApplicationTests {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Test
    void authenticationWorks() {
        UsernamePasswordAuthenticationToken token =
            UsernamePasswordAuthenticationToken.unauthenticated(
                "user",
                "password"
            );

        Authentication result = authenticationManager.authenticate(token);
        assertThat(result.isAuthenticated()).isTrue();
    }

    @Test
    void methodSecurityWorks() {
        // Test method security in native image
    }
}

Build Native Image

# Maven
./mvnw -Pnative native:compile

# Gradle
./gradlew nativeCompile

# Run native image
./target/native-security-application

# Or with Gradle
./build/native/nativeCompile/native-security-application

Common Issues and Solutions

Reflection Errors

Problem: ClassNotFoundException or NoSuchMethodException at runtime.

Solution: Register missing types in RuntimeHints:

@Bean
public RuntimeHintsRegistrar reflectionHints() {
    return (hints, classLoader) -> {
        hints.reflection()
            .registerType(MissingClass.class,
                MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS,
                MemberCategory.INVOKE_PUBLIC_METHODS,
                MemberCategory.DECLARED_FIELDS
            );
    };
}

Resource Loading Errors

Problem: Resources not found in native image.

Solution: Register resource patterns:

hints.resources()
    .registerPattern("path/to/resource.properties")
    .registerPattern("templates/*.html");

Proxy Generation Errors

Problem: Dynamic proxy errors at runtime.

Solution: Register proxy interfaces:

hints.proxies()
    .registerJdkProxy(InterfaceA.class, InterfaceB.class);

Serialization Errors

Problem: Serialization fails in native image.

Solution: Register serializable types:

hints.serialization()
    .registerType(SerializableClass.class);

Performance Characteristics

Native Image Benefits:

  • Startup time: 10-100x faster (seconds to milliseconds)
  • Memory footprint: 5-10x smaller
  • Predictable performance: No JIT warm-up

Trade-offs:

  • Build time: Longer compilation (minutes vs seconds)
  • Dynamic features: Limited reflection/proxying
  • Binary size: Larger than JAR files

Typical Metrics:

Traditional JVM:
- Startup: 2-5 seconds
- Memory: 200-500 MB

Native Image:
- Startup: 50-200 milliseconds
- Memory: 50-100 MB

Best Practices

  1. Use automatic hint discovery - Let Spring Security auto-discover hints when possible
  2. Test native builds early - Don't wait until production to test native compilation
  3. Register custom types explicitly - Register all custom authentication/authorization types
  4. Use @RegisterReflectionForBinding - Annotate DTOs and configuration classes
  5. Avoid dynamic class loading - Use compile-time configuration when possible
  6. Profile native image - Use GraalVM profiling tools to identify issues
  7. Keep dependencies AOT-compatible - Ensure all dependencies support native image
  8. Document custom hints - Maintain documentation for custom hint registrations

AOT Processing

Spring Security's AOT processor automatically:

  • Scans for security annotations
  • Generates hint contributions
  • Processes security configurations
  • Registers authentication/authorization types
  • Configures Jackson serialization
  • Sets up method security proxies

No additional configuration required for standard Spring Security features.

Troubleshooting

Enable Verbose Logging

# Native build with detailed logging
./mvnw -Pnative native:compile \
  -Dverbose \
  -H:+ReportExceptionStackTraces \
  -H:+PrintClassInitialization

Inspect Generated Hints

# Generate AOT hints without building
./mvnw spring-boot:process-aot

# Inspect generated files
ls target/spring-aot/main/

Debug Native Image

# Build with debug info
native-image \
  --debug-attach \
  -H:+ReportExceptionStackTraces \
  -jar application.jar

See Also

  • Method Security
  • Authorization
  • Authentication
  • GraalVM Native Image documentation
  • Spring Boot Native documentation