Observability :: Spring Security Why Spring Overview Trending Generative AI Cloud Architecture Patterns Microservices Reactive Event Driven Application Types Web Applications Serverless Batch Learn Getting Started Quickstart Guides Academy Courses Get Certified Projects Overview Projects Spring Boot Spring Framework Spring Cloud Spring AI Spring Data Spring Integration Spring Batch Spring Security Foundational Projects Micrometer Reactor Development Tools Spring Tools Spring Initializr Resources Blog Release Calendar Version Mappings Release Highlights Security Advisories GitHub Orgs Spring Projects Spring Cloud Community Overview Events Authors Enterprise Overview Long-term Support Automated Upgrades Governance and Compliance Modern App Development light Spring Security 7.0.7-SNAPSHOT Search Overview Prerequisites Community What’s New Preparing for 8.0 Migrating to 7 Servlet Authorization OAuth 2.0 SAML 2.0 Reactive Getting Spring Security Javadoc Features Authentication Password Storage Authorization Protection Against Exploits CSRF HTTP Headers HTTP Requests Integrations REST Client HTTP Service Clients Cryptography Spring Data Java’s Concurrency APIs Jackson Localization Project Modules Samples Servlet Applications Getting Started Architecture Authentication Authentication Architecture Username/Password Reading Username/Password Form Basic Digest Password Storage In Memory JDBC UserDetails CredentialsContainer Password Erasure UserDetailsService PasswordEncoder DaoAuthenticationProvider LDAP Multi-Factor Authentication Persistence Passkeys One-Time Token Session Management Remember Me Anonymous Pre-Authentication JAAS CAS X509 Run-As Logout Authentication Events Kerberos Introduction Reference Samples Appendices Authorization Authorization Architecture Authorize HTTP Requests Method Security Domain Object Security ACLs Authorization Events OAuth2 OAuth2 Log In Core Configuration Advanced Configuration OIDC Logout OAuth2 Client Core Interfaces and Classes OAuth2 Authorization Grants OAuth2 Client Authentication OAuth2 Authorized Clients OAuth2 Resource Server JWT Opaque Token Multitenancy Bearer Tokens DPoP-bound Access Tokens Protected Resource Metadata OAuth2 Authorization Server Getting Started Configuration Model Core Model / Components Protocol Endpoints SAML2 SAML2 Log In SAML2 Log In Overview SAML2 Authentication Requests SAML2 Authentication Responses SAML2 Logout SAML2 Metadata Migrating from Spring Security SAML Extension Protection Against Exploits Cross Site Request Forgery (CSRF) Security HTTP Response Headers HTTP HttpFirewall Integrations Concurrency Localization Servlet APIs Spring Data Spring MVC WebSocket Spring’s CORS Support JSP Taglib Observability Configuration Java Configuration Kotlin Configuration Namespace Configuration Testing Method Security MockMvc Support MockMvc Setup Security RequestPostProcessors Mocking Users Mocking CSRF Mocking Form Login Mocking HTTP Basic Mocking OAuth2 Mocking Logout Security RequestBuilders Security ResultMatchers Security ResultHandlers Appendix Database Schemas XML Namespace Authentication Services Web Security Method Security LDAP Security WebSocket Security Proxy Server Configuration FAQ Reactive Applications Getting Started Authentication X.509 Authentication Logout Session Management Concurrent Sessions Control Authorization Authorize HTTP Requests EnableReactiveMethodSecurity OAuth2 OAuth2 Log In Core Configuration Advanced Configuration OIDC Logout OAuth2 Client Core Interfaces and Classes OAuth2 Authorization Grants OAuth2 Client Authentication OAuth2 Authorized Clients OAuth2 Resource Server JWT Opaque Token Multitenancy Bearer Tokens Protection Against Exploits CSRF Headers HTTP Requests ServerWebExchangeFirewall Integrations CORS RSocket Observability Testing Testing Method Security Testing Web Security WebTestClient Setup Testing Authentication Testing CSRF Testing OAuth 2.0 Testing X509 WebFlux Security GraalVM Native Image Support Method Security Search Edit this Page GitHub Project Stack Overflow Spring Security Reactive Applications Integrations Observability This version is still in development and is not considered stable yet. For the latest stable version, please use Spring Security 7.1.0! Observability Spring Security integrates with Spring Observability out-of-the-box for tracing; though it’s also quite simple to configure for gathering metrics. Tracing When an ObservationRegistry bean is present, Spring Security creates traces for: the filter chain the ReactiveAuthenticationManager, and the ReactiveAuthorizationManager Boot Integration For example, consider a simple Boot application: Java Kotlin @SpringBootApplication public class MyApplication { @Bean public ReactiveUserDetailsService userDetailsService() { return new MapReactiveUserDetailsManager( User.withDefaultPasswordEncoder() .username("user") .password("password") .authorities("app") .build() ); } @Bean ObservationRegistryCustomizer<ObservationRegistry> addTextHandler() { return (registry) -> registry.observationConfig().observationHandler(new ObservationTextPublisher()); } public static void main(String[] args) { SpringApplication.run(ListenerSamplesApplication.class, args); } } @SpringBootApplication class MyApplication { @Bean fun userDetailsService(): ReactiveUserDetailsService { MapReactiveUserDetailsManager( User.withDefaultPasswordEncoder() .username("user") .password("password") .authorities("app") .build() ); } @Bean fun addTextHandler(): ObservationRegistryCustomizer<ObservationRegistry> { return registry: ObservationRegistry -> registry.observationConfig() .observationHandler(ObservationTextPublisher()); } fun main(args: Array<String>) { runApplication<MyApplication>(*args) } } And a corresponding request: ?> http -a user:password :8080 Will produce the following output (indentation added for clarity): START - name='http.server.requests', contextualName='null', error='null', lowCardinalityKeyValues=[], highCardinalityKeyValues=[], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@5dfdb78', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=0.00191856, duration(nanos)=1918560.0, startTimeNanos=101177265022745}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@121549e0'] START - name='spring.security.http.chains', contextualName='spring.security.http.chains.before', error='null', lowCardinalityKeyValues=[chain.size='14', filter.section='before'], highCardinalityKeyValues=[request.line='/'], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@3932a48c', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=4.65777E-4, duration(nanos)=465777.0, startTimeNanos=101177276300777}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@562db70f'] STOP - name='spring.security.http.chains', contextualName='spring.security.http.chains.before', error='null', lowCardinalityKeyValues=[chain.size='14', filter.section='before'], highCardinalityKeyValues=[request.line='/'], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@3932a48c', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=0.003733105, duration(nanos)=3733105.0, startTimeNanos=101177276300777}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@562db70f'] START - name='spring.security.authentications', contextualName='null', error='null', lowCardinalityKeyValues=[authentication.failure.type='Optional', authentication.method='UserDetailsRepositoryReactiveAuthenticationManager', authentication.request.type='UsernamePasswordAuthenticationToken'], highCardinalityKeyValues=[], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@574ba6cd', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=3.21015E-4, duration(nanos)=321015.0, startTimeNanos=101177336038417}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@49202cc7'] STOP - name='spring.security.authentications', contextualName='null', error='null', lowCardinalityKeyValues=[authentication.failure.type='Optional', authentication.method='UserDetailsRepositoryReactiveAuthenticationManager', authentication.request.type='UsernamePasswordAuthenticationToken', authentication.result.type='UsernamePasswordAuthenticationToken'], highCardinalityKeyValues=[], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@574ba6cd', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=0.37574992, duration(nanos)=3.7574992E8, startTimeNanos=101177336038417}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@49202cc7'] START - name='spring.security.authorizations', contextualName='null', error='null', lowCardinalityKeyValues=[object.type='SecurityContextServerWebExchange'], highCardinalityKeyValues=[], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@6f837332', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=2.65687E-4, duration(nanos)=265687.0, startTimeNanos=101177777941381}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@7f5bc7cb'] STOP - name='spring.security.authorizations', contextualName='null', error='null', lowCardinalityKeyValues=[authorization.decision='true', object.type='SecurityContextServerWebExchange'], highCardinalityKeyValues=[authentication.authorities='[app]', authorization.decision.details='AuthorizationDecision [granted=true]'], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@6f837332', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=0.039239047, duration(nanos)=3.9239047E7, startTimeNanos=101177777941381}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@7f5bc7cb'] START - name='spring.security.http.secured.requests', contextualName='null', error='null', lowCardinalityKeyValues=[], highCardinalityKeyValues=[], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@2f33dfae', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=3.1775E-4, duration(nanos)=317750.0, startTimeNanos=101177821377592}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@63b0d28f'] STOP - name='spring.security.http.secured.requests', contextualName='null', error='null', lowCardinalityKeyValues=[], highCardinalityKeyValues=[], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@2f33dfae', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=0.219901971, duration(nanos)=2.19901971E8, startTimeNanos=101177821377592}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@63b0d28f'] START - name='spring.security.http.chains', contextualName='spring.security.http.chains.after', error='null', lowCardinalityKeyValues=[chain.size='14', filter.section='after'], highCardinalityKeyValues=[request.line='/'], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@40b25623', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=3.25118E-4, duration(nanos)=325118.0, startTimeNanos=101178044824275}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@3b6cec2'] STOP - name='spring.security.http.chains', contextualName='spring.security.http.chains.after', error='null', lowCardinalityKeyValues=[chain.size='14', filter.section='after'], highCardinalityKeyValues=[request.line='/'], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@40b25623', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=0.001693146, duration(nanos)=1693146.0, startTimeNanos=101178044824275}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@3b6cec2'] STOP - name='http.server.requests', contextualName='null', error='null', lowCardinalityKeyValues=[], highCardinalityKeyValues=[], map=[class io.micrometer.tracing.handler.TracingObservationHandler$TracingContext='io.micrometer.tracing.handler.TracingObservationHandler$TracingContext@5dfdb78', class io.micrometer.core.instrument.LongTaskTimer$Sample='SampleImpl{duration(seconds)=0.784320641, duration(nanos)=7.84320641E8, startTimeNanos=101177265022745}', class io.micrometer.core.instrument.Timer$Sample='io.micrometer.core.instrument.Timer$Sample@121549e0'] Manual Configuration For a non-Spring Boot application, or to override the existing Boot configuration, you can publish your own ObservationRegistry and Spring Security will still pick it up. Java Kotlin Xml @SpringBootApplication public class MyApplication { @Bean public ReactiveUserDetailsService userDetailsService() { return new MapReactiveUserDetailsManager( User.withDefaultPasswordEncoder() .username("user") .password("password") .authorities("app") .build() ); } @Bean ObservationRegistry observationRegistry() { ObservationRegistry registry = ObservationRegistry.create(); registry.observationConfig().observationHandler(new ObservationTextPublisher()); return registry; } public static void main(String[] args) { SpringApplication.run(ListenerSamplesApplication.class, args); } } @SpringBootApplication class MyApplication { @Bean fun userDetailsService(): ReactiveUserDetailsService { MapReactiveUserDetailsManager( User.withDefaultPasswordEncoder() .username("user") .password("password") .authorities("app") .build() ); } @Bean fun observationRegistry(): ObservationRegistry { ObservationRegistry registry = ObservationRegistry.create() registry.observationConfig().observationHandler(ObservationTextPublisher()) return registry } fun main(args: Array<String>) { runApplication<MyApplication>(*args) } } <sec:http auto-config="true" observation-registry-ref="ref"> <sec:intercept-url pattern="/**" access="authenticated"/> </sec:http> <!-- define and configure ObservationRegistry bean --> Disabling Observability If you don’t want any Spring Security observations, in a Spring Boot application you can publish a ObservationRegistry.NOOP @Bean. However, this may turn off observations for more than just Spring Security. Instead, you can publish a SecurityObservationSettings like the following: Java Kotlin @Bean SecurityObservationSettings noSpringSecurityObservations() { return SecurityObservationSettings.noObservations(); } @Bean fun noSpringSecurityObservations(): SecurityObservationSettings { return SecurityObservationSettings.noObservations() } and then Spring Security will not wrap any filter chains, authentications, or authorizations in their ObservationXXX counterparts. There is no facility for disabling observations with XML support. Instead, simply do not set the observation-registry-ref attribute. You can also disable security for only a subset of Security’s observations. For example, the SecurityObservationSettings bean excludes the filter chain observations by default. So, you can also do: Java Kotlin @Bean SecurityObservationSettings defaultSpringSecurityObservations() { return SecurityObservationSettings.withDefaults().build(); } @Bean fun defaultSpringSecurityObservations(): SecurityObservationSettings { return SecurityObservationSettings.withDefaults().build() } Or you can turn on and off observations individually, based on the defaults: Java Kotlin @Bean SecurityObservationSettings allSpringSecurityObservations() { return SecurityObservationSettings.withDefaults() .shouldObserveFilterChains(true).build(); } @Bean fun allSpringSecurityObservations(): SecurityObservationSettings { return SecurityObservabilityDefaults.builder() .shouldObserveFilterChains(true).build() } For backward compatibility, all Spring Security observations are made unless a SecurityObservationSettings is published. Trace Listing Spring Security tracks the following spans on each request: spring.security.http.requests - a span that wraps the entire filter chain, including the request spring.security.http.chains.before - a span that wraps the receiving part of the security filters spring.security.http.chains.after - a span that wraps the returning part of the security filters spring.security.http.secured.requests - a span that wraps the now-secured application request spring.security.http.unsecured.requests - a span that wraps requests that Spring Security does not secure spring.security.authentications - a span that wraps authentication attempts spring.security.authorizations - a span that wraps authorization attempts spring.security.http.chains.before + spring.security.http.secured.requests + spring.security.http.chains.after = spring.security.http.requests spring.security.http.chains.before + spring.security.http.chains.after = Spring Security’s part of the request Spring Security Stable 7.1.0 7.0.6 6.5.11 Snapshot 7.1.1-SNAPSHOT 7.0.7-SNAPSHOT 6.5.12-SNAPSHOT Related Spring Documentation Spring Framework Spring Security Spring Authorization Server Spring LDAP Spring Security Kerberos Spring Session Spring Vault Spring GraphQL All Docs... Copyright © 2005 - Broadcom. All Rights Reserved. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. Terms of Use • Privacy • Trademark Guidelines • Thank you • Your California Privacy Rights • Cookie Settings Apache®, Apache Tomcat®, Apache Kafka®, Apache Cassandra™, and Apache Geode™ are trademarks or registered trademarks of the Apache Software Foundation in the United States and/or other countries. Java™, Java™ SE, Java™ EE, and OpenJDK™ are trademarks of Oracle and/or its affiliates. Kubernetes® is a registered trademark of the Linux Foundation in the United States and other countries. Linux® is the registered trademark of Linus Torvalds in the United States and other countries. Windows® and Microsoft® Azure are registered trademarks of Microsoft Corporation. “AWS” and “Amazon Web Services” are trademarks or registered trademarks of Amazon.com Inc. or its affiliates. All other trademarks and copyrights are property of their respective owners and are only mentioned for informative purposes. Other names may be trademarks of their respective owners. Search in all Spring Docs