Getting Started

SAPL Node is both a PDP server and a CLI tool in a single binary. Applications query it for authorization decisions via HTTP. You use the same binary on your workstation to create, sign, and inspect policy bundles and to generate client credentials. Whether you run the server directly or in Docker, you will need the binary locally for these operations.

Getting the Binary

Download the archive for your platform from the releases page.

On Linux or macOS, extract the archive:

tar xzf sapl-node-*-linux-amd64.tar.gz

On Windows, extract the .zip file using Explorer or any archive tool.

Each archive contains the sapl-node binary (ready to run, no runtime dependencies), the LICENSE, and a README.md. Place the binary somewhere on your PATH or in the directory where you plan to run the server.

Verify the installation:

./sapl-node --version

Quick Start

This walkthrough sets up a working node from scratch, deploys a policy, and queries the PDP with curl.

Create a working directory with the required structure:

mkdir -p my-node/config my-node/policies

Create my-node/config/application.yml. This disables TLS and authentication for a quick local test:

io.sapl:
  pdp.embedded:
    config-path: policies
    policies-path: policies
  node:
    allowNoAuth: true

server:
  port: 8080
  ssl:
    enabled: false

Create my-node/policies/pdp.json. This tells the PDP which combining algorithm to use when multiple policies apply:

{
  "algorithm": {
    "votingMode": "PRIORITY_PERMIT",
    "defaultDecision": "DENY",
    "errorHandling": "ABSTAIN"
  },
  "variables": {}
}

Create my-node/policies/tick.sapl. This policy uses the built in time PIP to grant access only when the current second is divisible by 5:

policy "tick"
permit
  time.secondOf(<time.now>) % 5 == 0

The <time.now> attribute is a stream. It emits the current UTC timestamp once per second. Every time a new value arrives, the PDP re evaluates the policy and pushes an updated decision to all connected clients.

Start the server:

cd my-node && ./sapl-node

In a separate terminal, request a one shot decision:

curl -s http://localhost:8080/api/pdp/decide-once -H 'Content-Type: application/json' -d '{"subject":"anyone","action":"read","resource":"clock"}'

The response is a single JSON object. Depending on the current second, the decision is either PERMIT or NOT_APPLICABLE.

Now try the streaming endpoint. This is where SAPL shows its strength. The PDP holds the connection open and pushes a new decision every time the policy evaluation result changes:

curl -N http://localhost:8080/api/pdp/decide -H 'Content-Type: application/json' -d '{"subject":"anyone","action":"read","resource":"clock"}'

Watch the output. Every few seconds, the decision flips between PERMIT and NOT_APPLICABLE as the current time crosses a multiple of five. The application does not need to poll. The PDP pushes changes as they happen.

Press Ctrl+C to stop the stream. The PDP cleans up the subscription automatically.

Try editing tick.sapl while the streaming curl is running. Change % 5 to % 10 and save. The PDP detects the change, recompiles the policy, and pushes an updated decision on the same connection. No restart needed.

While the server is running, you can also check its operational state. The health endpoint shows whether policies loaded successfully:

curl -s http://localhost:8080/actuator/health | python3 -m json.tool

You should see "status": "UP" with a pdps detail block showing the state LOADED, the active combining algorithm, and the number of loaded documents. If a policy has a syntax error, the state changes to ERROR and the health status drops to DOWN.

The info endpoint shows PDP configuration (this endpoint requires authentication in production, but works unauthenticated in this setup since allowNoAuth is enabled):

curl -s http://localhost:8080/actuator/info | python3 -m json.tool

For Prometheus metrics, Kubernetes probes, and decision logging, see Monitoring.

Directory Layout

The working directory you just created follows the standard layout:

my-node/
  sapl-node
  config/
    application.yml
  policies/
    pdp.json
    tick.sapl

The server looks for config/application.yml on startup. The config-path and policies-path properties point to the policy directory. For bundle based deployments, the policies directory holds .saplbundle files instead of raw .sapl files. See Policy Sources for the different source types and Configuration for the full property reference.

Running with Docker

For container deployments, the server runs inside Docker while you use the local sapl-node binary for CLI operations like bundle creation and credential generation.

The container image is ghcr.io/heutelbeck/sapl-node. Mount your policies directory into the container and configure the server via environment variables:

docker run -p 8080:8080 -v ./policies:/pdp/data:ro -e SERVER_SSL_ENABLED=false -e SERVER_PORT=8080 -e SERVER_ADDRESS=0.0.0.0 -e IO_SAPL_NODE_ALLOWNOAUTH=true -e IO_SAPL_PDP_EMBEDDED_POLICIESPATH=/pdp/data ghcr.io/heutelbeck/sapl-node:4.0.0-SNAPSHOT

The -v ./policies:/pdp/data:ro flag maps your local policies/ directory into the container at /pdp/data. The :ro suffix makes the mount read only, which is good practice since the server only reads policies.

Environment variables follow Spring Boot’s naming convention: dots become underscores, camelCase becomes uppercase. For example, io.sapl.node.allowBasicAuth becomes IO_SAPL_NODE_ALLOWBASICAUTH. See Configuration for all available properties.

You can also mount a full application.yml instead of using individual environment variables:

docker run -p 8443:8443 -v ./config:/pdp/config:ro -v ./policies:/pdp/data:ro ghcr.io/heutelbeck/sapl-node:4.0.0-SNAPSHOT

CLI Reference

The sapl-node binary doubles as a CLI tool. These commands run locally without starting the server. Use them to manage bundles and generate credentials for your application.yml.

bundle create

Creates a .saplbundle archive from a directory of .sapl files and a pdp.json.

sapl-node bundle create -i <dir> -o <file>
Option Description
-i, --input Input directory containing policies.
-o, --output Output .saplbundle file.

bundle sign

Signs a bundle with an Ed25519 private key. Overwrites the input bundle unless -o is specified.

sapl-node bundle sign -b <file> -k <key> [options]
Option Description
-b, --bundle Bundle file to sign.
-k, --key Ed25519 private key file (PEM, PKCS8).
-o, --output Output file. Defaults to overwriting the input.
--key-id Key identifier stored in the manifest. Defaults to "default".

bundle verify

Verifies a signed bundle against an Ed25519 public key. Returns exit code 0 on success and 1 on failure.

sapl-node bundle verify -b <file> -k <key> [options]
Option Description
-b, --bundle Bundle file to verify.
-k, --key Ed25519 public key file (PEM, X.509).
--check-expiration Fails if the signature has expired.

bundle inspect

Displays bundle contents, signature status, configuration, and policy list.

sapl-node bundle inspect -b <file>
Option Description
-b, --bundle Bundle file to inspect.

bundle keygen

Generates an Ed25519 keypair for bundle signing.

sapl-node bundle keygen -o <prefix> [options]
Option Description
-o, --output Output prefix. Creates <prefix>.pem (private key) and <prefix>.pub (public key).
--force Overwrites existing files.

generate basic

Generates Basic Auth credentials. Prints the plaintext password and a ready to paste YAML block for application.yml.

sapl-node generate basic --id <id> --pdp-id <pdpId>
Option Description
-i, --id Client identifier.
-p, --pdp-id PDP identifier for multi tenant routing.

generate apikey

Generates an API key. Prints the plaintext key and a ready to paste YAML block for application.yml.

sapl-node generate apikey --id <id> --pdp-id <pdpId>
Option Description
-i, --id Client identifier.
-p, --pdp-id PDP identifier for multi tenant routing.

For authentication and TLS setup, see Security. For health checks and metrics, see Monitoring.