npm package: @loopfortress/jingle-cli
Description: A policy-driven JOSE Key Management Tool
Latest version: 0.0.5

LoopFortress Jingle CLI
=======================

Jingle is a policy-driven JOSE Key Management Framework with declarative config, CLI, and runtime engine.

## Features

**General**

- Uniform DX across symmetric + asymmetric + PBES2 + ECDH + AES-KW/GCMKW
- CLI for keygen, keystore and token operations

**Keygen**

- A declarative keygen architecture: spec → keystore → token factory (clean lifecycle flow)
- Purpose-based key groups (rotate under "access", "refresh", "userdata", etc.)
- Automatic kid assignment (user doesn’t have to care at all)
- Configurable key ID formatting (fun but harmless DX feature)

**Keystore**

- A type-safe JWK registry with strong typing for alg families & policies
- A clean keystore → runtime in-memory engine
- Optional external key import
- Optional strict/lenient policies and fallback logic for broken external integrations
- Automatic rotation with purpose groups

**Token Factory**

- Built-in JWT/JWS/JWE minting & verification
- A declarative token profile layer with mint & verify policies
- Mint & accept rules per token profile (structural authentication policy system)

## Library Usage

**`config/jingle/Keystore.yaml`**

- This Keystore.yaml is used to configure the keystore.
- It defines the key groups and their policies.
- The key groups are referenced in the token factory config.
- You don't need to mount this file in the docker-compose.yaml.
- It's used to generate the keystore at build time.

```yaml
version: '1.0'

forge:
  sig:
    demo-signer-key:
      alg: ES256
      policy:
        curve: P-256

  enc: {}
```

**`config/jingle/Keystore.json`**

- Use the Jingle CLI to generate the keystore to a location of your choice.
- In this example, we generat the keystore next to the Jingle.yaml config file (`Jinglestore.json`).

```shell
JINGLE_RC=config/jingle/Keystore.yaml jingle forge # use --force to overwrite an existing keystore
```

**`config/jingle/Factory.yaml`**

- This Jingle.yaml is used to configure the token factory and the keystore location.
- It defines the token profiles and their mint & accept rules.
- The token profiles are referenced in the app.

```yaml
version: '1.0'

keystoreLocation: /etc/jingle/Jinglestore.json

factory:
  # ===================== JWS Profiles =====================
  jws:
    demo-jws:
      description: "Demo Signer (JWS)"
      mint:
        group: demo-signer-key
        alg: ES256
      accept:
        kid: exact
        algs: [ES256]

  # ===================== JWE Profiles =====================
  jwe: {}

  # ===================== JWT Profiles =====================
  jwt: {}

  # ===================== JWN Profiles (JWE + JWS matrix) =====================
  jwn: {}
```

**`apps/index.ts`**

- Load the runtime and run validation to ensure the config is healthy.
- The runtime is used to mint and verify tokens in the app.

```typescript
import { bootRuntimeOrCrash } from '@loopfortress/jingle-cli'

const rcFilePath = 'config/Factory.yaml'

console.log('Loading keys runtime', rcFilePath)

const r = async () => await bootRuntimeOrCrash(process.cwd(), rcFilePath)

export const runtime = await r()
const ok = runtime.factory.doctor()
if (!ok) {
  console.error('Keys runtime failed to load')
  process.exit(1)
}

console.log('Keys runtime loaded')

const jws = await runtime.factory.mintJWS('demo-jws', {/* payload */})
try {
  const payload = await runtime.factory.verifyJWS('demo-jws', jws)
  console.log('JWS verified:', payload)
} catch (error) {
  console.error('Error verifying JWS:', error)
}
```

**docker-compose.yaml**

- Define a volume mount for the Jingle.yaml config file and a keystore.
- The keystore is assumed to be previously generated.

```yaml
version: '3.9'
services:
  demo:
    volumes:
      - ./app/index.ts:/workspace/index.ts:ro
      - ./config/jingle/Factory.yaml:/workspace/config/Factory.yaml:ro
      - ./config/jingle/Jinglestore.json:/etc/jingle/Jinglestore.json:ro
```

## CLI