---
title: "Secure Spring Boot APIs with API Key Authentication"
description: "Secure your Spring Boot API using a shared secret."
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/java/springboot/secure-header"
framework: "Spring Boot"
language: "Java"
authStrategy: "shared secret header"
pageType: use-case
---

# Secure Spring Boot APIs with API Key Authentication

Secure your Spring Boot API using a shared secret.

## How Zuplo Handles It

Put Zuplo in front of your Spring Boot backend to authenticate API keys and forward a shared secret header so your origin only accepts traffic from Zuplo.

## Spring Boot Backend Code

```java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

@Component
public class SharedSecretFilter extends OncePerRequestFilter {

    @Value("${shared.secret}")
    private String expectedSecret;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        String secret = request.getHeader("X-Shared-Secret");

        if (expectedSecret == null) {
            response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Server configuration error");
            return;
        }

        if (secret == null) {
            response.sendError(HttpStatus.UNAUTHORIZED.value(), "No secret provided");
            return;
        }

        try {
            if (!timingSafeEquals(secret, expectedSecret)) {
                response.sendError(HttpStatus.UNAUTHORIZED.value(), "Invalid secret");
                return;
            }
        } catch (NoSuchAlgorithmException e) {
            response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Error validating secret");
            return;
        }

        filterChain.doFilter(request, response);
    }

    private boolean timingSafeEquals(String a, String b) throws NoSuchAlgorithmException {
        byte[] aBytes = a.getBytes();
        byte[] bBytes = b.getBytes();

        if (aBytes.length != bBytes.length) {
            return false;
        }

        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] aDigest = digest.digest(aBytes);
        byte[] bDigest = digest.digest(bBytes);

        return Arrays.equals(aDigest, bDigest);
    }
}

// In your configuration class
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;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, SharedSecretFilter sharedSecretFilter) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/protected").authenticated()
                .and()
            .addFilterBefore(sharedSecretFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
}

// Example controller
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
@RequestMapping("/protected")
public class ProtectedController {

    @GetMapping
    public String getProtectedResource() {
        return "Access granted";
    }
}
```

## Example Request

```bash
curl -X GET \
  'https://your-api.zuplo.dev/your-route' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

## Learn More

- [API Key Authentication on Zuplo](https://zuplo.com/docs/policies/api-key-auth-inbound)
- [JWT Authentication on Zuplo](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound)
- [All use cases](https://zuplo.com/use-cases)
