Skip to main content

Commercial quickstart

Run the Ory Talos commercial (OEL) edition locally with Docker and Postgres. This guide pulls the published commercial image, starts a Postgres-backed instance, and walks through issued and imported API key flows. The curl examples are the default; the Ory Talos CLI is an alternative.

For the single-node OSS edition on SQLite, see the Open source quickstart.

Set up credentials​

  1. Download keyfile.json from the email you received.
  2. Authenticate with Google Cloud:
    gcloud auth activate-service-account --key-file=keyfile.json
    gcloud auth configure-docker europe-docker.pkg.dev

Pull the image​

docker pull europe-docker.pkg.dev/ory-artifacts/ory-enterprise-talos/talos-oel:26.2.8

Start Postgres​

docker network create talos-preview
docker run -d --name talos-postgres --network talos-preview \
-e POSTGRES_USER=talos -e POSTGRES_PASSWORD=talos -e POSTGRES_DB=talos \
-p 5432:5432 postgres:16-alpine

Configure Ory Talos​

Create config.yaml in your working directory:

serve:
http: { host: "0.0.0.0", port: 8080 }
metrics: { host: "0.0.0.0", port: 4422 }

credentials:
issuer: "http://localhost:8080"
api_keys:
default_ttl: "720h"
prefix: { current: "talos" }
derived_tokens:
default_ttl: "1h"
jwt:
signing_keys:
urls:
- "base64://eyAgImtleXMiOiBbICAgIHsgICAgICAiYWxnIjogIkVkRFNBIiwgICAgICAiY3J2IjogIkVkMjU1MTkiLCAgICAgICJkIjogIjl3VTNfV3p0dmx3TXg0SGlfN2dsSVduY09XNlVIR2I5amxDdDZEZkVGa2MiLCAgICAgICJraWQiOiAiZG9ja2VyLWRldi0wMDEiLCAgICAgICJrdHkiOiAiT0tQIiwgICAgICAidXNlIjogInNpZyIsICAgICAgIngiOiAiNGtTQTdtNU5jYnFDUC1mZk9fNGhQM2tsNHB0NGctLTNRQ21zQmwzb05lVSIgICAgfSAgXX0="
macaroon:
prefix: { current: "mc" }

db:
dsn: "postgres://talos:talos@talos-postgres:5432/talos?sslmode=disable"

secrets:
hmac: { current: "preview-hmac-secret-minimum-32-chars-long" }

cache: { type: "memory", ttl: "5m" }
multitenancy: { enabled: false }
log: { level: "info", format: "json" }
caution

This config embeds the development EdDSA JWK from deployments/docker/config/config.yaml. Replace it before any non-local use because the private key is published in the source tree.

Run database migrations​

Initialize the Postgres schema before the first server start:

docker run --rm --network talos-preview \
europe-docker.pkg.dev/ory-artifacts/ory-enterprise-talos/talos-oel:26.2.8 \
migrate up --database "postgres://talos:talos@talos-postgres:5432/talos?sslmode=disable"

Start Ory Talos​

docker run -d --name talos --network talos-preview \
-p 8080:8080 -p 4422:4422 \
-v "$PWD/config.yaml:/etc/talos/config.yaml:ro" \
europe-docker.pkg.dev/ory-artifacts/ory-enterprise-talos/talos-oel:26.2.8 \
serve --config /etc/talos/config.yaml

This starts a single-tenant commercial server that uses the in-memory cache.

Wait for the server to become ready​

# Wait for the health endpoint
for i in $(seq 1 30); do
if curl -sf http://localhost:8080/health/alive > /dev/null 2>&1; then
echo "Server is ready"
break
fi
sleep 1
done

CI runs the API examples below against the same published image on the talos-preview Docker network.

Set the base URL for the local server:

export TALOS_URL="${TALOS_URL:-http://localhost:8080}"

Issue an API key​

Create an issued key on the admin API and save its secret for later steps. For the complete field reference, see the IssueAPIKey API reference.

RESPONSE=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/issuedApiKeys" \
-H "Content-Type: application/json" \
-d '{
"name": "commercial-issued-key",
"actor_id": "commercial-user",
"scopes": ["read:profile", "write:profile"],
"ttl": "720h"
}')

echo "$RESPONSE" | jq .

export API_SECRET=$(echo "$RESPONSE" | jq -er '.secret')
export KEY_ID=$(echo "$RESPONSE" | jq -er '.issued_api_key.key_id')

The response returns issued_api_key metadata plus secret. The secret is shown only once, so store it securely.

Verify the issued key​

Send the issued key secret to the verify endpoint. For the full response fields and error codes, see the VerifyAPIKey API reference.

VERIFY_RESPONSE=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/apiKeys:verify" \
-H "Content-Type: application/json" \
-d "{\"credential\":\"$API_SECRET\"}")

echo "$VERIFY_RESPONSE" | jq .

A valid result returns is_valid: true plus the key's actor, scopes, issuer, and expiration.

Derive a JWT from the issued key​

Mint a short-lived JWT from the issued key with custom claims. For the full request and response schema, see the DeriveToken API reference.

RESPONSE=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/apiKeys:derive" \
-H "Content-Type: application/json" \
-d "{
\"credential\": \"$API_SECRET\",
\"algorithm\": \"TOKEN_ALGORITHM_JWT\",
\"ttl\": \"1h\",
\"custom_claims\": {\"role\": \"commercial-user\", \"environment\": \"demo\"}
}")

echo "$RESPONSE" | jq .

export JWT_TOKEN=$(echo "$RESPONSE" | jq -er '.token.token')

The derived token inherits the parent key's permissions and returns as token.token with its own expiry metadata.

Import an existing API key​

Import an existing key string into Ory Talos without rotating the credential. For the complete field reference, see the ImportAPIKey API reference.

export IMPORTED_RAW_KEY=sk_commercial_demo_001

RESPONSE=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/importedApiKeys" \
-H "Content-Type: application/json" \
-d "{
\"raw_key\": \"$IMPORTED_RAW_KEY\",
\"name\": \"commercial-imported-key\",
\"actor_id\": \"commercial-import-user\",
\"scopes\": [\"payments:read\", \"payments:write\"],
\"ttl\": \"720h\"
}")

echo "$RESPONSE" | jq .

export IMPORTED_KEY_ID=$(echo "$RESPONSE" | jq -er '.key_id')

Ory Talos stores a hash of the imported credential, not the raw key. The raw key is never returned after import.

Verify the imported key​

Imported keys use the same verify endpoint as issued keys. Ory Talos detects the credential type automatically.

VERIFY_RESPONSE=$(curl -s -X POST "$TALOS_URL/v2alpha1/admin/apiKeys:verify" \
-H "Content-Type: application/json" \
-d "{\"credential\":\"$IMPORTED_RAW_KEY\"}")

echo "$VERIFY_RESPONSE" | jq .

Stop the server​

docker rm -f talos talos-postgres
docker network rm talos-preview

Next steps​