---
title: "Secure undefined APIs with API Key Authentication"
description: undefined
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/java/springcloudgateway/secure-header"
framework: undefined
language: undefined
authStrategy: "shared secret header"
pageType: use-case
---

# Secure undefined APIs with API Key Authentication



## How Zuplo Handles It

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

## undefined Backend Code

```java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

@Component
@Order(1)
public class SharedSecretFilter implements GlobalFilter {

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

    @PostConstruct
    public void init() {
        if (!StringUtils.hasText(expectedSecret)) {
            throw new IllegalStateException("The SHARED_SECRET environment variable must be set");
        }
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        Optional<String> secretOpt = Optional.ofNullable(exchange.getRequest().getHeaders().getFirst("x-shared-secret"));

        if (secretOpt.isEmpty()) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        String secret = secretOpt.get();

        if (!constantTimeEquals(secret, expectedSecret)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    private boolean constantTimeEquals(String a, String b) {
        if (a.length() != b.length()) {
            return false;
        }
        byte[] aBytes = a.getBytes(StandardCharsets.UTF_8);
        byte[] bBytes = b.getBytes(StandardCharsets.UTF_8);

        int result = 0;
        for (int i = 0; i < aBytes.length; i++) {
            result |= aBytes[i] ^ bBytes[i];
        }
        return result == 0;
    }
}

// Example usage in application.yml
// spring:
//   cloud:
//     gateway:
//       routes:
//       - id: protected-route
//         uri: http://your-backend-service
//         predicates:
//         - Path=/protected
//         filters:
//         - Name=SharedSecretFilter
```

## 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)
