Information Security 9 min read

Implementing API Key Authentication in Spring Security for REST APIs

This tutorial explains how to secure a Spring Boot REST API using API‑key authentication by adding the necessary Maven dependency, creating a custom filter, extending AbstractAuthenticationToken, configuring Spring Security, implementing a controller, and testing the endpoint with and without the API key.

Architect's Guide
Architect's Guide
Architect's Guide
Implementing API Key Authentication in Spring Security for REST APIs

1. Overview

Security is crucial in REST API development because an insecure API can expose sensitive backend data, so organizations must pay attention to API security.

Spring Security offers various mechanisms to protect REST APIs, one of which is API keys—tokens supplied by clients when invoking an API.

This tutorial discusses how to implement API‑key‑based authentication in Spring Security.

2. REST API Security

Spring Security can protect REST APIs. Since REST APIs are stateless, sessions or cookies should not be used; instead, Basic authentication, API Keys, JWT, or OAuth2‑based tokens should be employed.

2.1. Basic Authentication

Basic authentication is a simple scheme where the client sends an Authorization header containing a Base64‑encoded username:password pair, and it is considered safe only over HTTPS or other secure transports.

2.2. OAuth2

OAuth2 is the industry‑standard open protocol for authentication and authorization, allowing resource owners to delegate access to clients via access tokens.

2.3. API Keys

Some REST APIs use API keys as a token that identifies the client without referencing an actual user; the key can be sent as a query parameter or in a request header.

3. Protecting REST API with API Keys

3.1 Add Maven Dependency

First declare the Spring Boot starter security dependency in pom.xml :

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

3.2 Create Custom Filter

The idea is to obtain the API key from the request header and validate it using our configuration, which requires adding a custom filter to the Spring Security chain.

We start from GenericFilterBean , a simple Spring implementation of javax.servlet.Filter :

public class AuthenticationFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
      throws IOException, ServletException {
        try {
            Authentication authentication = AuthenticationService.getAuthentication((HttpServletRequest) request);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (Exception exp) {
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
            PrintWriter writer = httpResponse.getWriter();
            writer.print(exp.getMessage());
            writer.flush();
            writer.close();
        }
        filterChain.doFilter(request, response);
    }
}

Only the doFilter() method needs to read the header, create an Authentication object, and place it into the current SecurityContext .

3.3 Extend AbstractAuthenticationToken

To turn the API key into an Authentication object, we extend AbstractAuthenticationToken :

public class ApiKeyAuthentication extends AbstractAuthenticationToken {
    private final String apiKey;

    public ApiKeyAuthentication(String apiKey, Collection
authorities) {
        super(authorities);
        this.apiKey = apiKey;
        setAuthenticated(true);
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @Override
    public Object getPrincipal() {
        return apiKey;
    }
}

3.4 Security Config

Register the custom filter before UsernamePasswordAuthenticationFilter in a SecurityFilterChain bean:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/**").authenticated()
            .and()
            .httpBasic()
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

The session policy is set to STATELESS because we are building a REST API.

3.5 ResourceController

Finally, create a simple controller exposing a GET endpoint /home :

@RestController
public class ResourceController {
    @GetMapping("/home")
    public String homeEndpoint() {
        return "Baeldung !";
    }
}

3.6 Disable Auto‑Configuration

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class})
public class ApiKeySecretAuthApplication {

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

4. Testing

Calling the endpoint without an API key returns a 401 Unauthorized error:

curl --location --request GET 'http://localhost:8080/home'

Adding the header X-API-KEY: Baeldung and requesting again returns 200 OK:

curl --location --request GET 'http://localhost:8080/home' \
--header 'X-API-KEY: Baeldung'

Source: baeldung.com/spring-boot-api-key-secret

JavaauthenticationREST APISpring SecurityAPI key
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.