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

# Secure Spark Java APIs with API Key Authentication

Secure your Spark Java API using a shared secret.

## How Zuplo Handles It

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

## Spark Java Backend Code

```java
import static spark.Spark.*;

import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;

import javax.crypto.SecretKey;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import spark.Filter;
import spark.Request;
import spark.Response;

public class SecureApiExample {

    public static void main(String[] args) {
        String expectedSecret = System.getenv("SHARED_SECRET");

        if (expectedSecret == null) {
            System.err.println("Error: SHARED_SECRET environment variable not set.");
            stop();
            return;
        }

        // Shared secret validation filter
        Filter validateSharedSecret = (Request request, Response response) -> {
            String secret = request.headers("x-shared-secret");

            if (secret == null) {
                halt(401, "{\"error\":\"No secret provided\"}");
                return;
            }

            try {
                if (!timingSafeEqual(secret, expectedSecret)) {
                    halt(401, "{\"error\":\"Invalid secret\"}");
                    return;
                }
            } catch (NoSuchAlgorithmException e) {
                halt(500, "{\"error\":\"Server configuration error\"}");
            }
        };

        // Apply the filter to a protected route
        before("/protected", validateSharedSecret);

        // Protected route example
        get("/protected", (req, res) -> {
            res.type("application/json");
            return "{\"message\":\"Access granted\"}";
        });

        // General error handling
        exception(Exception.class, (exception, request, response) -> {
            response.status(500);
            response.body("{\"error\":\"Internal server error\"}");
        });
    }

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

        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKey secretKey = new SecretKeySpec(aBytes, "HmacSHA256");
        mac.init(secretKey);

        byte[] aHash = mac.doFinal(aBytes);
        byte[] bHash = mac.doFinal(bBytes);

        if (aHash.length != bHash.length) {
            return false;
        }

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

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