Securing Spring Boot API With API Key and Secret

Last Updated : 4 Jun, 2026

Securing APIs is essential to ensure that only authorized clients can access application resources. One common approach is using an API Key and API Secret, which act as credentials sent with each request. Spring Security allows us to validate these credentials before granting access to protected endpoints.

  • API Key and Secret provide a simple authentication mechanism for APIs.
  • Requests are validated before accessing protected resources.
  • Spring Security filters can be used to intercept and authenticate API requests.

Major concepts

The following concepts are fundamental to understanding how API Key and Secret authentication works in Spring Security.

1. Authentication and Authorization

Authentication: It verifies the identity of the client making the request.

Example: Checking whether the provided API Key and Secret are valid.

Authorization:It determines whether the authenticated client has permission to access a resource.

Example: Allowing authenticated users to access /api/** endpoints.

2. API Key and Secret

  • API Key : A public identifier used to identify the client.
  • API Secret : A private credential used to verify the client.

3. Custom Authentication token

A custom authentication token stores the API Key and Secret during the authentication process.

  • Holds authentication credentials.
  • Maintains authentication state.

4. Custom Authentication Filter

The filter intercepts incoming HTTP requests and extracts credentials from request headers.

  • Read API Key and Secret.
  • Create authentication token.

5. Security Configuration

Spring Security configuration defines:

  • Protected endpoints.
  • Authentication rules.

6. API Endpoint

The controller exposes secured REST endpoints that can only be accessed after successful authentication.

Implementation to Secure Spring Boot API With API Key and Secret

We can develop the simple spring boot application that can demonstrates the securing spring boot API key and secret of the application.

Step 1: Create the Spring project.

Create a new Spring Boot project using Spring Initializr and add the required dependencies,

  • Spring Web
  • Spring Security
  • Lombok
  • Spring DevTools

pom.xml

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>spring-boot-secure-API</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-boot-secure-API</name>
    <description>spring-boot-secure-API</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

After the creation of the project has done, the folder structure will be like below image.

Folder Structure

Step 2: Configure the Application properties

Open application.properties file and add the configuration for the server port in the project.

spring.application.name=spring-boot-secure-api
server.port=8081

Step 3: Create the ApiKeyAuthentication Token class

Create a custom authentication token class.

  • Store API Key.
  • Store API Secret.
Java
package org.example.springbootsecureapi.config;


import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;

import java.util.Collection;



public class ApiKeyAuthenticationToken extends AbstractAuthenticationToken {

    private final String apiKey;
    private final String apiSecret;

    public ApiKeyAuthenticationToken(String apiKey, String apiSecret) {
        super(null);
        this.apiKey = apiKey;
        this.apiSecret = apiSecret;
        setAuthenticated(false);
    }

    public ApiKeyAuthenticationToken(String apiKey, String apiSecret, Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.apiKey = apiKey;
        this.apiSecret = apiSecret;
        super.setAuthenticated(true);
    }

    @Override
    public Object getCredentials() {
        return this.apiSecret;
    }

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

    @Override
    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        }
        super.setAuthenticated(false);
    }

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
    }
}

Step 4: Create the ApiKeyAuthFilter class

Create a custom filter that intercepts requests.

  • Extract API Key header.
  • Extract API Secret header.
Java
package org.example.springbootsecureapi.config;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;

import java.io.IOException;



public class ApiKeyAuthFilter extends AbstractAuthenticationProcessingFilter {

    private static final String API_KEY_HEADER = "API-Key";
    private static final String API_SECRET_HEADER = "API-Secret";

    public ApiKeyAuthFilter(RequestMatcher requiresAuth) {
        super(requiresAuth);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException {
        String apiKey = request.getHeader(API_KEY_HEADER);
        String apiSecret = request.getHeader(API_SECRET_HEADER);

        if (apiKey == null || apiSecret == null) {
            throw new RuntimeException("Missing API Key or Secret");
        }

        Authentication auth = new ApiKeyAuthenticationToken(apiKey, apiSecret);
        return getAuthenticationManager().authenticate(auth);
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        super.successfulAuthentication(request, response, chain, authResult);
        chain.doFilter(request, response);
    }
}

Step 5: Create the SecurityConfig class

Create the SecurityConfig class.

  • Register custom filter.
  • Protect API endpoints.
Java
package org.example.springbootsecureapi.config;



import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;



import java.util.Collections;



import java.util.Collections;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        ApiKeyAuthFilter filter = new ApiKeyAuthFilter(new AntPathRequestMatcher("/api/**"));
        filter.setAuthenticationManager(authentication -> {
            String apiKey = (String) authentication.getPrincipal();
            String apiSecret = (String) authentication.getCredentials();

            if ("valid-api-key".equals(apiKey) && "valid-api-secret".equals(apiSecret)) {
                return new ApiKeyAuthenticationToken(apiKey, apiSecret, Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")));
            } else {
                authentication.setAuthenticated(false);
            }

            return authentication;
        });

        http
                .csrf().disable()
                .authorizeRequests(authorizeRequests ->
                        authorizeRequests
                                .requestMatchers("/api/**").authenticated()
                                .anyRequest().permitAll()
                )
                .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}

Step 6: Create the ApiController class

  • Create a secured REST controller.
  • Provides a protected API endpoint.
Java
package org.example.springbootsecureapi.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/data")
    public String getSecureData() {
        return "This is Spring Boot API secured data!";
    }
}

Step 7: Main Class

Create the Spring Boot entry point.

Java
package org.example.springbootsecureapi;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootSecureApiApplication {

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

}

Step 8: Run the application

Once, we run the application, it will start at port 8081.

Application Runs

Step 9: Endpoint Testing

1. Endpoint without the api key and secret

GET http://localhost:8081/api/data

Then show the error like below:

Missing API Key and secret

Output:

API Missing Error Message

2. Endpoint Test with API key and secret

GET http://localhost:8081/api/data

Add the API key and secret in Header section.

API Key : valid-api-key
API Secret: valid-api-key

Output:

API Key and Secret


By the following these steps, we can secure the Spring Boot API using API keys and secrets. This method ensures that only the clients with valid credentials can access the API endpoints and thereby adding the extra layer of the security to the Spring Boot application.

Comment

Explore