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

# Secure Vert.x APIs with API Key Authentication

Secure your Vert.x API using a shared secret.

## How Zuplo Handles It

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

## Vert.x Backend Code

```java
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

public class SecureApiVerticle extends AbstractVerticle {

  private static final String SHARED_SECRET_ENV = "SHARED_SECRET";

  @Override
  public void start() {
    Router router = Router.router(vertx);

    // Shared secret validation middleware
    router.route().handler(BodyHandler.create());
    router.route("/protected/*").handler(this::validateSharedSecret);

    // Protected route example
    router.get("/protected/resource").handler(ctx ->
      ctx.json(new JsonObject().put("message", "Access granted"))
    );

    vertx.createHttpServer().requestHandler(router).listen(8888);
  }

  private void validateSharedSecret(RoutingContext ctx) {
    String secret = ctx.request().getHeader("x-shared-secret");
    String expectedSecret = System.getenv(SHARED_SECRET_ENV);

    if (expectedSecret == null) {
      ctx.response().setStatusCode(500).end("Server configuration error");
      return;
    }

    if (secret == null) {
      ctx.response().setStatusCode(401).end("No secret provided");
      return;
    }

    try {
      if (!timingSafeEqual(secret, expectedSecret)) {
        ctx.response().setStatusCode(401).end("Invalid secret");
        return;
      }
    } catch (NoSuchAlgorithmException e) {
      ctx.response().setStatusCode(500).end("Internal server error");
      return;
    }

    ctx.next();
  }

  private boolean timingSafeEqual(String a, String b) throws NoSuchAlgorithmException {
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    byte[] hashA = digest.digest(a.getBytes(StandardCharsets.UTF_8));
    byte[] hashB = digest.digest(b.getBytes(StandardCharsets.UTF_8));

    return Arrays.equals(hashA, hashB);
  }

  public static void main(String[] args) {
    Vertx vertx = Vertx.vertx();
    vertx.deployVerticle(new SecureApiVerticle());
  }
}
```

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