Apikee

Java

apikee for Java — Spring Boot with zero-config autoconfiguration.

Java

Maven Central

Installation

<dependency>
  <groupId>dev.apikee</groupId>
  <artifactId>apikee-spring</artifactId>
  <version>0.1.0</version>
</dependency>

Gradle:

implementation("dev.apikee:apikee-spring:0.1.0")

Zero-config Spring Boot

Add to application.yml — the filter and Swagger customizer are autoconfigured:

apikee:
  secrets:
    - ${APIKEE_LOCAL_SECRET}       # required
  header-name: x-api-key           # default

  # Server mode (optional)
  server-key:  ${APIKEE_SERVER_KEY:}
  project-env: ${APIKEE_PROJECT_ENV:my-app-production}
  fail-open:   true

That's it. No @Bean declarations needed for the standard setup.

Accessing claims

Claims are stored as a request attribute after the filter runs:

@GetMapping("/data")
public ResponseEntity<?> getData(HttpServletRequest request) {
    ApikeeClaims claims = (ApikeeClaims) request.getAttribute("apikee.claims");
    return ResponseEntity.ok(Map.of(
        "tenant", claims.tenant(),
        "scopes", claims.scopes()
    ));
}

Issuing keys

Inject ApikeeKeyEngine anywhere in your application:

@Service
public class KeyService {

    private final ApikeeKeyEngine engine;

    public KeyService(ApikeeKeyEngine engine) {
        this.engine = engine;
    }

    public String issueKey(String tenant, List<String> scopes) {
        return engine.create(
            KeyOptions.builder()
                .tenant(tenant)
                .scopes(scopes)
                .expiresAt(Instant.now().plus(Duration.ofDays(90)))
                .meta(Map.of("plan", "pro"))
                .build()
        );
    }
}

Swagger / SpringDoc

Auto-configured when springdoc-openapi-starter-webmvc-ui is on the classpath. The ApikeeOpenApiCustomizer bean injects ApikeeAuth into the spec and applies it globally.

To customise manually:

@Bean
public ApikeeOpenApiCustomizer apikeeSwagger() {
    return new ApikeeOpenApiCustomizer("x-api-key");
}

Scope enforcement

Spring doesn't have a built-in scope guard, but the pattern is straightforward:

private void requireScope(ApikeeClaims claims, String... required) {
    for (String s : required) {
        if (claims.scopes().contains(s)) return;
    }
    throw new ResponseStatusException(HttpStatus.FORBIDDEN,
        "Required scope(s): " + String.join(", ", required));
}

@DeleteMapping("/items/{id}")
public ResponseEntity<?> deleteItem(@PathVariable int id, HttpServletRequest req) {
    requireScope(claims(req), "admin");
    // ...
}

Manual configuration

When you need full control:

@Configuration
public class ApikeeConfig {

    @Bean
    public ApikeeKeyEngine engine() {
        return new ApikeeKeyEngine(List.of(
            System.getenv("APIKEE_LOCAL_SECRET")
        ));
    }

    @Bean
    public FilterRegistrationBean<ApikeeFilter> filter(ApikeeKeyEngine engine) {
        var filter = new ApikeeFilter(engine, "x-api-key", null);
        var bean   = new FilterRegistrationBean<>(filter);
        bean.addUrlPatterns("/*");
        bean.setOrder(-100);
        return bean;
    }
}

Configuration reference

PropertyTypeDefaultDescription
apikee.secretsList<String>requiredSigning secrets. First is current.
apikee.header-nameStringx-api-keyHeader to read the key from.
apikee.server-keyStringnullapikee.dev project key. Enables server mode.
apikee.project-envStringnullapikee.dev project_env slug.
apikee.auto-register-endpointsbooleantrueRegister endpoints on first request.
apikee.fail-openbooleantrueAllow through if server call fails.
apikee.server-timeout-mslong3000Timeout for apikee.dev calls.
apikee.filter-orderint-100Servlet filter order.

Source

github.com/apikee-dev/java

On this page