Quick start

May 6, 2026 · View on GitHub

Install

<dependency>
  <groupId>io.github.davidalmeidac</groupId>
  <artifactId>sealed-env-spring-boot-starter</artifactId>
  <version>0.1.0-alpha.1</version>
</dependency>

Or for non-Spring Java apps:

<dependency>
  <groupId>io.github.davidalmeidac</groupId>
  <artifactId>sealed-env-core</artifactId>
  <version>0.1.0-alpha.1</version>
</dependency>

Requires Java 17+. Bouncy Castle is the only runtime dependency (for Argon2id).

Spring Boot integration

The starter auto-registers an EnvironmentPostProcessor that runs before property binding, so @Value and @ConfigurationProperties see the decrypted values.

   JVM startup


   ┌─────────────────────────┐
   │ SpringApplication.run() │
   └────────────┬────────────┘
                │  postProcessEnvironment()

   ┌──────────────────────────────────────┐
   │ SealedEnvEnvironmentPostProcessor    │
   │ ──────────────────────────────────── │
   │  1. read .env.sealed                 │
   │  2. decrypt with SEALED_ENV_KEY      │
   │  3. wipe master key from memory      │
   └────────────┬─────────────────────────┘
                │  addPropertySource("sealedEnv", ...)

   ┌──────────────────────────────────────┐
   │      Spring Environment              │
   │   (sealedEnv source registered)      │
   └────────────┬─────────────────────────┘


   ┌──────────────────────────────────────┐
   │  your beans                          │
   │  ─────────────────────────────────   │
   │  @Value("${API_KEY}")                │
   │  ─▶ sees decrypted value             │
   └──────────────────────────────────────┘

Configure

application.yml:

sealed-env:
  enabled: true
  path: .env.sealed
  fail-fast: true       # production: hard fail if file missing/key wrong
  override: false       # explicit application properties win

Run

SEALED_ENV_KEY=$(cat master.key) \
SEALED_ENV_SIGNING_KEY=$(cat signing.key) \
java -jar your-app.jar

For enterprise mode you also pass SEALED_ENV_UNSEAL_TOKEN (generated fresh on each deploy by the operator running sealed-env unseal) and SEALED_ENV_DEPLOY_ID (typically the commit SHA).

Programmatic API (no Spring)

import io.github.davidalmeidac.sealedenv.SealedEnv;

var opts = new SealedEnv.LoadOptions();
opts.path = Path.of(".env.sealed");
opts.populateSystem = true;   // copy to System.getProperties

Map<String, String> env = SealedEnv.loadSealed(opts);
String apiKey = env.get("API_KEY");

Cross-stack: Java decrypting a Node-sealed file

This is automatic. The .env.sealed file format is identical across both implementations. The Node CLI writes KDF=scrypt (Node 22 stdlib has no Argon2id); the Java reader supports both Argon2id and scrypt natively.

   Node writer                                  Java writer
   (KDF=scrypt)                                 (KDF=argon2id)
        │                                            │
        └──────────────┐              ┌──────────────┘
                       ▼              ▼
                  ┌────────────────────────┐
                  │     .env.sealed        │
                  │   (single canonical    │
                  │    v1 wire format)     │
                  └────────┬───────┬───────┘
                           │       │
              ┌────────────┘       └─────────────┐
              ▼                                  ▼
       ┌─────────────┐                    ┌─────────────┐
       │ Node reads  │                    │ Java reads  │
       │ either KDF  │* (only scrypt)     │ either KDF  │
       └─────────────┘                    └─────────────┘

   * Node 22 stdlib has no Argon2id. If a Java-written file with
     KDF=argon2id reaches a Node-only consumer, the reader surfaces
     UNSUPPORTED_KDF with a clear message; v0.2.x will ship a wasm
     Argon2id to close this gap.