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

# Secure Zuul APIs with API Key Authentication

Secure your Zuul API using a shared secret.

## How Zuplo Handles It

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

## Zuul Backend Code

```java
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import javax.servlet.http.HttpServletRequest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

@Component
public class SharedSecretFilter extends ZuulFilter {

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

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String secret = request.getHeader("X-Shared-Secret");

        if (expectedSecret == null || expectedSecret.isEmpty()) {
            ctx.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
            ctx.setResponseBody("{\"error\":\"Server configuration error\"}");
            ctx.setSendZuulResponse(false);
            return null;
        }

        if (secret == null || secret.isEmpty()) {
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            ctx.setResponseBody("{\"error\":\"No secret provided\"}");
            ctx.setSendZuulResponse(false);
            return null;
        }

        try {
            if (!timingSafeEqual(secret, expectedSecret)) {
                ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
                ctx.setResponseBody("{\"error\":\"Invalid secret\"}");
                ctx.setSendZuulResponse(false);
            }
        } catch (NoSuchAlgorithmException e) {
            ctx.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
            ctx.setResponseBody("{\"error\":\"Server error\"}");
            ctx.setSendZuulResponse(false);
        }

        return null;
    }

    private boolean timingSafeEqual(String a, String b) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] aBytes = digest.digest(a.getBytes());
        byte[] bBytes = digest.digest(b.getBytes());
        return Arrays.equals(aBytes, bBytes);
    }
}
```

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