> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowx.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# License service setup

> Set up the License service (formerly License Engine) — manages platform and application licensing, subscription plans, feature quotas, and usage tracking across SaaS and self-hosted deployments.

## Dependencies

Before setting up the License service, ensure you have the following dependencies in place:

* **[Organization Manager](/5.9/setup-guides/organization-manager-setup)** for organization lifecycle events and realm resolution
* **PostgreSQL** database for storing license and usage data
* **Kafka** for event-driven communication with other FlowX.AI services
* **Redis** for caching and master election
* **Keycloak** (or compatible OAuth2 provider) for authentication and authorization
* **SpiceDB** for fine-grained authorization

## Infrastructure prerequisites

| Component  | Description                                            |
| ---------- | ------------------------------------------------------ |
| PostgreSQL | Dedicated database for license data                    |
| Kafka      | Message broker for inter-service communication         |
| Redis      | Caching layer and distributed lock for master election |
| Keycloak   | Identity provider for service authentication           |
| SpiceDB    | Authorization service for fine-grained access control  |

***

## Configuration

### Authorization configuration

| Environment Variable                                                   | Description                                     | Default Value                          |
| ---------------------------------------------------------------------- | ----------------------------------------------- | -------------------------------------- |
| `SECURITY_TYPE`                                                        | Security type (JWT public key validation)       | `jwt-public-key`                       |
| `SECURITY_OAUTH2_BASESERVERURL`                                        | Base URL of the Keycloak server                 |                                        |
| `SECURITY_OAUTH2_SAREALM`                                              | Service accounts realm ID                       | `00000002-0002-4002-8002-000000000002` |
| `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_MAINIDENTITY_CLIENTID`     | Service account client ID                       | `flowx-license-sa`                     |
| `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_MAINIDENTITY_CLIENTSECRET` | Service account client secret (Keycloak-issued) |                                        |
| `FLOWX_LIB_SECURITY_SERVICES_ORGANIZATIONMANAGER_BASEURL`              | Organization manager URL                        | `http://organization-manager:80`       |

***

### PostgreSQL configuration

The License service uses its own dedicated PostgreSQL database.

| Environment Variable         | Description                        | Default Value                                   |
| ---------------------------- | ---------------------------------- | ----------------------------------------------- |
| `SPRING_DATASOURCE_URL`      | JDBC connection URL for PostgreSQL | `jdbc:postgresql://flowxlicensedb:5432/license` |
| `SPRING_DATASOURCE_USERNAME` | Database username                  | `postgres`                                      |
| `SPRING_DATASOURCE_PASSWORD` | Database password                  | -                                               |

<Note>
  **PostgreSQL and Redis credentials: plain env vars still work.** The License service is a standard Spring Boot service — it reads the `SPRING_DATASOURCE_*` and `SPRING_DATA_REDIS_*` environment variables shown here. The `postgresql.servers/credentials` and `redis.servers/credentials` blocks in the FlowX Helm chart's `values.yaml` are the chart's own secret-to-env-var mapping; they exist to template the same plain env vars from your secrets. You can keep injecting credentials through plain environment variables exactly as before.
</Note>

<Warning>
  Ensure the database is created before deploying the service. The License service will manage its own schema migrations via Liquibase.
</Warning>

***

### Redis configuration

The License service includes Redis in its configuration for caching and master election. Configure Redis connection using the standard Redis environment variables.

**Quick reference:**

| Environment Variable         | Description                   | Example Value | Status          |
| ---------------------------- | ----------------------------- | ------------- | --------------- |
| `SPRING_DATA_REDIS_HOST`     | Redis server hostname         | `localhost`   | **Recommended** |
| `SPRING_DATA_REDIS_PORT`     | Redis server port             | `6379`        | **Recommended** |
| `SPRING_DATA_REDIS_PASSWORD` | Redis authentication password | -             | **Recommended** |
| `REDIS_TTL`                  | Cache TTL in milliseconds     | `5000000`     | Optional        |

<Info>
  Both `SPRING_DATA_REDIS_*` and `SPRING_REDIS_*` variable prefixes are supported. The `SPRING_DATA_REDIS_*` prefix is the modern Spring Boot standard and is recommended for new deployments.
</Info>

<Info>
  For advanced Redis deployment modes (Sentinel, Cluster) and SSL/TLS setup, see the [Redis Configuration](/5.1/setup-guides/redis-configuration) guide. Note that Sentinel and Cluster modes are only supported by the Events Gateway service.
</Info>

<Note>
  Redis is configured but not actively used by the License service at this time. It is included as part of the standard Spring service setup and may be used in future versions.
</Note>

***

### Kafka configuration

#### Core Kafka settings

| Environment Variable             | Description                    | Default Value      |
| -------------------------------- | ------------------------------ | ------------------ |
| `SPRING_KAFKA_BOOTSTRAP_SERVERS` | Address of the Kafka server(s) | `localhost:9092`   |
| `KAFKA_MESSAGE_MAX_BYTES`        | Maximum message size (bytes)   | `52428800` (50 MB) |

#### Topic naming configuration

| Environment Variable             | Description                         | Default Value |
| -------------------------------- | ----------------------------------- | ------------- |
| `KAFKA_TOPIC_NAMING_PACKAGE`     | Package prefix for topic names      | `ai.flowx.`   |
| `KAFKA_TOPIC_NAMING_ENVIRONMENT` | Environment segment for topic names | ` `           |
| `KAFKA_TOPIC_NAMING_VERSION`     | Version suffix for topic names      | `.v1`         |
| `KAFKA_TOPIC_NAMING_SEPARATOR`   | Primary separator for topic names   | `.`           |
| `KAFKA_TOPIC_NAMING_SEPARATOR2`  | Secondary separator for topic names | `-`           |

#### Kafka topics

The License service consumes events from the following topics:

| Topic               | Default Value                     | Description                                         |
| ------------------- | --------------------------------- | --------------------------------------------------- |
| License usage       | `ai.flowx.license.usage.v1`       | Receives usage reporting events from other services |
| Organization events | `ai.flowx.organization.events.v1` | Receives organization lifecycle events              |

#### Kafka consumer threads

| Environment Variable                         | Description                                   | Default Value |
| -------------------------------------------- | --------------------------------------------- | ------------- |
| `KAFKA_CONSUMER_THREADS_LICENSE_USAGE`       | Thread count for license usage consumer       | `6`           |
| `KAFKA_CONSUMER_THREADS_ORGANIZATION_EVENTS` | Thread count for organization events consumer | `2`           |
| `KAFKA_AUTH_EXCEPTION_RETRY_INTERVAL`        | Retry interval after auth exception (seconds) | `10`          |

***

### CAS lib configuration (SpiceDB)

| Environment Variable                         | Description                                                                                                                                                                             | Default Value |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `FLOWX_SPICEDB_HOST`                         | SpiceDB hostname                                                                                                                                                                        | `spicedb`     |
| `FLOWX_SPICEDB_PORT`                         | SpiceDB gRPC port                                                                                                                                                                       | `50051`       |
| `FLOWX_SPICEDB_TOKEN`                        | SpiceDB authentication token                                                                                                                                                            | -             |
| `FLOWX_LIB_CASCLIENT_RUNTIME_IMPLEMENTATION` | Runtime authorization backend used by the CAS client. `CUSTOM` routes checks through authorization-system; `SPICEDB` delegates to SpiceDB. Keep the default unless instructed by FlowX. | `CUSTOM`      |

***

### FlowX SaaS connection (self-hosted only)

| Environment Variable            | Description                                                                                                                                                                                              | Default Value |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `FLOWX_LICENSE_ORGANIZATION_ID` | Organization ID provided by FlowX during self-hosted registration. Initialized with the `notset` sentinel so the OAuth client can start before the self-hosted client injects the real value at runtime. | `notset`      |
| `FLOWX_LICENSE_KEY`             | License key issued by FlowX for this self-hosted deployment.                                                                                                                                             | -             |
| `FLOWX_LICENSE_AUTH_SERVER_URL` | Auth endpoint provided by FlowX licensing.                                                                                                                                                               | -             |
| `FLOWX_LICENSE_SERVER_URL`      | License API endpoint provided by FlowX licensing.                                                                                                                                                        | -             |

<Warning>
  These values are provided by FlowX during the organization registration process. Without them, the License service cannot validate the platform license or report usage data.

  Your network must allow outbound connectivity to the FlowX SaaS endpoints configured above.
</Warning>

### Usage upload tuning

The License service periodically uploads usage records to FlowX SaaS. These defaults work for most deployments and only need tuning for very large organizations:

| Environment Variable                          | Description                                                         | Default Value |
| --------------------------------------------- | ------------------------------------------------------------------- | ------------- |
| `FLOWX_SCHEDULER_USAGEUPLOAD_LOADFETCHSIZE`   | Number of usage records loaded from the database per scheduler tick | `100`         |
| `FLOWX_SCHEDULER_USAGEUPLOAD_UPLOADBATCHSIZE` | Number of usage records sent per upload request to FlowX SaaS       | `500`         |

***

### Logging configuration

| Environment Variable      | Description                    | Default Value |
| ------------------------- | ------------------------------ | ------------- |
| `LOGGING_LEVEL_APP`       | Application-specific log level | `INFO`        |
| `LOGGING_LEVEL_LIQUIBASE` | Liquibase migration log level  | `INFO`        |

***

## Secrets management

The License service requires several secrets to be configured. These should be stored securely and referenced via Kubernetes secrets or a secrets management solution.

| Secret Name                                                             | Description                     |
| ----------------------------------------------------------------------- | ------------------------------- |
| `SPRING_DATASOURCE_PASSWORD`                                            | PostgreSQL database password    |
| `SPRING_REDIS_PASSWORD`                                                 | Redis authentication password   |
| `SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_MAINIDENTITY_CLIENT_SECRET` | Keycloak service account secret |
| `FLOWX_SPICEDB_TOKEN`                                                   | SpiceDB authentication token    |

***

## Deployment

### Helm values example

Below is an example Helm values configuration for deploying the License service:

```yaml theme={"system"}
fullnameOverride: license

image:
  repository: <your-registry>/license

replicaCount: 1

env:
  SPRING_PROFILES_ACTIVE: production

  # PostgreSQL
  SPRING_DATASOURCE_URL: jdbc:postgresql://postgresql:5432/license
  SPRING_DATASOURCE_USERNAME: postgres

  # Kafka
  SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092

  # Security
  SECURITY_TYPE: jwt-public-key
  SECURITY_OAUTH2_BASESERVERURL: https://keycloak.example.com/auth
  SECURITY_OAUTH2_SAREALM: 00000002-0002-4002-8002-000000000002

  # Redis
  SPRING_REDIS_HOST: redis-master

  # SpiceDB
  FLOWX_SPICEDB_HOST: spicedb
  FLOWX_SPICEDB_PORT: 50051

# Secrets configuration
extraEnvVarsMultipleSecretsCustomKeys:
  - name: postgresql-generic
    secrets:
      SPRING_DATASOURCE_PASSWORD: postgresql-password-key
  - name: redis-generic
    secrets:
      SPRING_REDIS_PASSWORD: redis-password
  - name: flowx-auth
    secrets:
      SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_MAINIDENTITY_CLIENT_SECRET: keycloakLicenseClientSecret
  - name: spicedb-generic
    secrets:
      FLOWX_SPICEDB_TOKEN: spicedb-token

rbac:
  create: true

ingress:
  enabled: false

podLabels:
  flowx.ai/network-log: "true"
  flowx.ai/egress-s-kafka: "true"
  flowx.ai/egress-s-postgresql: "true"
  flowx.ai/egress-s-redis: "true"
  flowx.ai/routing-name: "license"
  flowx.ai/prometheus-scrape: "license"
```

### Network policies

The License service requires network access to the following services:

| Service    | Purpose                      | Pod Label                      |
| ---------- | ---------------------------- | ------------------------------ |
| Kafka      | Message broker communication | `flowx.ai/egress-s-kafka`      |
| PostgreSQL | Primary data storage         | `flowx.ai/egress-s-postgresql` |
| Redis      | Caching and master election  | `flowx.ai/egress-s-redis`      |
| Keycloak   | Authentication               | `flowx.ai/egress-s-keycloak`   |
| SpiceDB    | Authorization                | `flowx.ai/egress-s-spicedb`    |

***

## Monitoring

The License service exposes Prometheus metrics for monitoring. Turn on scraping by setting the pod label:

```yaml theme={"system"}
podLabels:
  flowx.ai/prometheus-scrape: "license"
```

### Health endpoints

| Endpoint            | Description                 |
| ------------------- | --------------------------- |
| `/actuator/health`  | Health check endpoint       |
| `/actuator/metrics` | Prometheus metrics endpoint |
| `/actuator/info`    | App info endpoint           |

***

## Verify your setup

<Check>
  The License service pod is running and healthy: `kubectl get pods -l app=license`
</Check>

<Check>
  The health endpoint returns HTTP 200: `curl http://license:8080/actuator/health`
</Check>

<Check>
  Database migrations completed successfully — check pod logs for `Liquibase: Update has been successful`
</Check>

<Check>
  SpiceDB connection is established — check pod logs for successful CAS client initialization
</Check>

<Check>
  Kafka topics `ai.flowx.license.usage.v1` and `ai.flowx.organization.events.v1` exist and the service can consume from them
</Check>

***

## Ingress and CORS

The License service is exposed externally on the admin host. Routing is configured through the FlowX Helm chart, which renders either a Kubernetes Ingress (default) or a Gateway API HTTPRoute per service. CORS handling lives in the service code; only the allowed-origins list is deployment-specific.

### Service route

| Host group | External path | Backend receives |
| ---------- | ------------- | ---------------- |
| admin      | `/license`    | `/`              |

The path is set through `services.license.ingress.admin.path` (or `services.license.gateway.admin.paths`) in the chart values.

### CORS configuration

| Environment Variable            | Description                                                                                                                                                                                   | Default Value |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `APPLICATION_CORS_ALLOW_ORIGIN` | Comma-separated list of origins allowed to call this service from the browser. Supports wildcard subdomains. Must include every Designer domain that issues browser requests against License. | `-`           |

Allowed methods, allowed headers (including `Authorization`, `Content-Type`, `Fx-Workspace-Id`), and credential handling are baked into the service's `application.yaml` with safe defaults. Override these only if you have a non-standard requirement.

For the complete route reference, Gateway API HTTPRoute configuration, and route customization, see the [ingress configuration guide](./ingress-configuration).

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Database connection failures">
    **Symptoms:** Service fails to start with database connection errors.

    **Solutions:**

    1. Verify the `license` database exists in PostgreSQL
    2. Check that the database user has appropriate permissions
    3. Ensure network connectivity between the pod and PostgreSQL service
    4. Verify the JDBC URL format is correct
  </Accordion>

  <Accordion title="SpiceDB connection failures">
    **Symptoms:** Authorization errors or service fails to initialize CAS client.

    **Solutions:**

    1. Verify SpiceDB is running and reachable at the configured host and port
    2. Check that the SpiceDB token is correct
    3. Ensure network policies allow gRPC traffic to SpiceDB on port `50051`
    4. Review pod logs for specific CAS client error messages
  </Accordion>

  <Accordion title="Kafka consumer issues">
    **Symptoms:** License usage events or organization events not being processed.

    **Solutions:**

    1. Verify Kafka bootstrap servers are reachable
    2. Check that the `ai.flowx.license.usage.v1` and `ai.flowx.organization.events.v1` topics exist
    3. Ensure the service has consumer permissions on the topics
    4. Check consumer group offsets for lag
  </Accordion>

  <Accordion title="Service account authentication errors">
    **Symptoms:** 401/403 errors when communicating with other FlowX services.

    **Solutions:**

    1. Verify the Keycloak service account `flowx-license-sa` is properly configured
    2. Check that client secrets match between configuration and Keycloak
    3. Ensure the service account has the `view-users` client role assigned
    4. Verify the service account realm UUID is correct
  </Accordion>
</AccordionGroup>

***

## Related resources

<CardGroup cols={2}>
  <Card title="Redis Configuration" icon="database" href="./redis-configuration">
    Complete Redis setup including Sentinel and Cluster modes
  </Card>

  <Card title="Access Management" icon="lock" href="./access-management/access-management-overview">
    Configure roles and access rights
  </Card>

  <Card title="SpiceDB Configuration" icon="shield-halved" href="./spicedb">
    Fine-grained authorization setup
  </Card>

  <Card title="IAM Configuration" icon="key" href="./access-management/configuring-an-iam-solution">
    Identity and access management setup including License service account
  </Card>
</CardGroup>
