Api Key Exposure in Spring Boot with Bearer Tokens
Api Key Exposure in Spring Boot with Bearer Tokens — how this specific combination creates or exposes the vulnerability
When API keys are handled as Bearer tokens in a Spring Boot application, several specific implementation patterns and configuration gaps can lead to exposure. A common risk arises when developers pass API keys via HTTP headers such as Authorization: Bearer <token> but inadvertently log these headers. In Spring Boot, if the incoming request is logged at an appropriate level (e.g., DEBUG or TRACE) by an embedded container or a filter, the Authorization header can be written to logs, exposing the token to anyone with access to log files or log aggregation systems.
Another exposure vector involves error handling and debugging endpoints. Spring Boot Actuator, if exposed in production, can reveal environment details and, in some configurations, request or response attributes. If a developer accidentally echoes the token in error responses or stack traces—such as when a custom exception handler includes the full header value—the token can be surfaced to unauthenticated or low-privilege attackers. Misconfigured CORS policies can also broaden the attack surface by allowing origins that should not receive sensitive credentials, indirectly facilitating token leakage through cross-origin requests.
Additionally, improper configuration of Spring Security can leave Bearer token endpoints or resource-server endpoints accessible without adequate authentication. For example, if a developer secures only specific paths with http.authorizeRequests() but omits broader matchers, some endpoints that accept Bearer tokens might remain publicly reachable. This can lead to enumeration or token replay if tokens are transmitted without transport-layer protections or if TLS termination is misconfigured, causing tokens to be sent in cleartext on internal networks.
Tokens can also be exposed through client-side storage or browser developer tools when frontend applications include Bearer tokens in requests originating from JavaScript. Although Spring Boot serves as the backend, insecure frontend practices—such as storing tokens in localStorage or failing to use short-lived tokens combined with refresh mechanisms—amplify the impact of any accidental logging or exposure on the backend. The combination of verbose logging, overly permissive security configurations, and insufficient transport controls creates a scenario where Bearer-based API keys are more likely to be unintentionally revealed.
Finally, integration with external services or microservices can propagate tokens insecurely. If Spring Boot forwards requests to downstream services and includes the original Authorization header without validation or sanitization, the token may traverse internal networks without additional protection. Without mutual TLS or service-level token binding, this chain of trust can be broken, leading to exposure of the API key across multiple runtime boundaries.
Bearer Tokens-Specific Remediation in Spring Boot — concrete code fixes
Remediation focuses on preventing unnecessary exposure of Bearer tokens in logs, error messages, and misconfigured security rules. Avoid logging headers directly. Instead of enabling DEBUG logging for org.apache.catalina.connector.Request or org.springframework.web.filter, use structured logging that excludes sensitive headers. For example, configure a custom OncePerRequestFilter to scrub headers before logging:
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
public class HeaderScrubbingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
// Wrap request to remove sensitive headers from getHeader before logging
HttpServletRequest wrappedRequest = new HttpServletRequestWrapper(request) {
@Override
public String getHeader(String name) {
if ("Authorization".equalsIgnoreCase(name)) {
return "[secure]";
}
return super.getHeader(name);
}
};
filterChain.doFilter(wrappedRequest, response);
}
}
Ensure Spring Security is configured to require authentication for endpoints that accept Bearer tokens and to use proper HTTP security headers. A typical secure setup includes:
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorize -> authorize
.antMatchers("/public/**").permitAll()
.antMatchers("/api/**").authenticated()
.anyRequest().denyAll()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt() // or .opaqueToken() for API key style validation
)
.csrf().disable()
.headers(headers -> headers
.contentSecurityPolicy("default-src 'self'")
.and()
.httpStrictTransportSecurity()
);
return http.build();
}
}
Validate token usage on the server side and avoid echoing raw token values in responses or exceptions. Use short-lived tokens and refresh flows where feasible, and ensure TLS is enforced via application.properties:
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=changeit
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=tomcat
Audit dependencies and actuator exposure. Limit Actuator endpoints and disable sensitive ones in production:
management.endpoints.web.exposure.include=health,info
management.endpoint.health.show-details=never
When integrating with downstream services, forward only necessary metadata and avoid re-using the original Authorization header unless required. Use service accounts with limited scope instead of propagating user-level tokens internally.