Information Security 8 min read

Implementing API Key Authentication in Spring Security for REST APIs

This tutorial explains how to secure REST APIs by implementing API‑key based authentication using Spring Security, covering the necessary Maven dependencies, custom filter creation, token handling, security configuration, controller setup, and testing with curl commands.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Implementing API Key Authentication in Spring Security for REST APIs

Security is crucial for REST API development because insecure APIs can expose sensitive backend data. Spring Security offers mechanisms such as API keys to protect APIs.

REST APIs are stateless, so authentication should rely on Basic authentication, API Keys, JWT, or OAuth2 tokens rather than sessions or cookies.

API keys act as tokens that identify clients without referencing actual users and can be sent via query strings or request headers.

1. Add Maven Dependency

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

2. Create a Custom Filter that extracts the API key from the request header and sets an Authentication object in the security context.

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);
    }
}

The doFilter() method retrieves the API key from the header and creates an Authentication object.

3. Implement Authentication Service to validate the key.

public class AuthenticationService {
    private static final String AUTH_TOKEN_HEADER_NAME = "X-API-KEY";
    private static final String AUTH_TOKEN = "Baeldung";

    public static Authentication getAuthentication(HttpServletRequest request) {
        String apiKey = request.getHeader(AUTH_TOKEN_HEADER_NAME);
        if ((apiKey == null) || !apiKey.equals(AUTH_TOKEN)) {
            throw new BadCredentialsException("Invalid API Key");
        }
        return new ApiKeyAuthentication(apiKey, AuthorityUtils.NO_AUTHORITIES);
    }
}

4. Extend AbstractAuthenticationToken to represent the API‑key authentication.

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; }
}

5. Security Configuration registers the custom filter before UsernamePasswordAuthenticationFilter and disables CSRF and session state.

@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();
    }
}

6. Resource Controller provides a protected endpoint.

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

7. Disable Auto‑Configuration for security classes.

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class})
public class ApiKeySecretAuthApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiKeySecretAuthApplication.class, args);
    }
}

8. Testing – Without an API key, a GET request to http://localhost:8080/home returns 401. Adding the header X-API-KEY: Baeldung returns 200 with the expected response.

JavaauthenticationREST APISpring SecurityAPI key
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

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.