---
title: "Auth0"
description: "Configure Auth0 for deployment"
source: "Guardian Platform"
---
## Overview

The Guardian Platform integrates with Auth0 for user authentication and authorization.

**Required Auth0 applications:**

- **Platform API (M2M)** – Machine-to-machine app for backend API token validation and the Governance Service's startup organization sync
- **Auth Service Backend (M2M)** – Machine-to-machine app for user and organization management via the Auth0 Management API
- **Governance Worker (M2M)** – Machine-to-machine app for the platform's automated governance workflows
- **Guardian (SPA)** – Single Page Application for frontend authentication

The platform also needs an Auth0 Organization for its users and two Auth0 Actions that add the platform's claims to user and worker tokens.

The deployment repository's `auth0-bootstrap` Helm chart automates most of this: it runs a one-time Kubernetes Job that creates the applications, API, grants, initial admin user, and Actions via the Auth0 Management API. Run it **before** deploying the platform chart - the services need valid client credentials at startup.

**This guide covers:**

- Creating Auth0 applications (bootstrap chart, Auth0 CLI, or Dashboard)
- Configuring API permissions and scopes
- Setting up organization support for multi-tenancy
- Deploying the Auth0 Actions
- Configuring the Helm chart for Auth0

## Prerequisites

- Auth0 tenant (sign up at auth0.com if needed)
- Auth0 tenant domain (e.g. `your-tenant.us.auth0.com`)
- `kubectl` and `helm` access to the deployment namespace
- [`jq`](https://jqlang.org/download/) 1.6 or later, to read the bootstrap's generated credentials
- A clone of the [deployment repository](./prerequisites.mdx#deployment-repository) for the `auth0-bootstrap` chart and the Auth0 Action sources
- [Auth0 CLI](https://github.com/auth0/auth0-cli#installation) installed (for the manual setup)

## Helm Configuration

Add the following to the `values.yaml` and `secrets.yaml` files. The quick start's [last step](#7-update-chart-values) says where each placeholder comes from; the manual setup fills them in step by step.

`values.yaml`:

```yaml
auth-service:
  config:
    idp:
      provider: "auth0"
      issuer: "https://<auth0-domain>/"
      auth0:
        domain: "<auth0-domain>"
        managementAudience: "https://<auth0-domain>/api/v2/"
        apiIdentifier: "https://<domain>"

governance-service:
  config:
    authProvider: "auth0"
    auth0Domain: "<auth0-domain>"

guardian:
  config:
    authProvider: "auth0"
    auth0Domain: "<auth0-domain>"
    auth0ClientId: "<spa-client-id>"
    auth0Audience: "https://<domain>"

# Post-install hook: seeds the governance database with the organization
# and the platform admin
auth0:
  createOrganization: true
  organizationName: "guardian" # Must match the Auth0 Organization name
  displayName: "Guardian Platform"
  createPlatformAdmin: true
  platformAdminEmail: "<admin-email>"
  domain: "<auth0-domain>"
```

`secrets.yaml`:

```yaml
global:
  secrets:
    create: true
    auth:
      provider: "auth0"
      auth0:
        secretName: "platform-auth0"
        values:
          clientId: "<platform-api-client-id>"
          clientSecret: "<platform-api-client-secret>"
          mgmtClientId: "<auth-service-client-id>"
          mgmtClientSecret: "<auth-service-client-secret>"
    authService:
      secretName: "platform-auth-service"
      values:
        apiSecret: "<auth-service-api-secret>" # Must equal the post-login Action's AUTH_SERVICE_API_SECRET
        jwtSecret: "<jwt-secret>" # Generate with: openssl rand -base64 32
    governanceWorker:
      secretName: "platform-governance-worker"
      values:
        encryptionKey: "<worker-encryption-key>" # Generate with: openssl rand -base64 32
        clientId: "<worker-client-id>"
        clientSecret: "<worker-client-secret>"
```

## Quick Start (Bootstrap Chart - Recommended)

Create a Management API application for the bootstrap, run the `auth0-bootstrap` chart, add the Auth0 Organization, and copy the generated credentials into the platform's chart values, in seven steps.

### 1. Create the Bootstrap M2M Application

The bootstrap job calls the Auth0 Management API with its own Machine-to-Machine application. In the Auth0 Dashboard:

1. Go to **Applications** > **Applications** > **Create Application**, choose **Machine to Machine Applications**, and name it `Governance Bootstrap M2M`
2. Authorize it for the **Auth0 Management API** with these scopes:
   - `read:clients`, `create:clients`, `update:clients`
   - `read:resource_servers`, `create:resource_servers`, `update:resource_servers`
   - `read:client_grants`, `create:client_grants`, `update:client_grants`
   - `read:users`, `create:users`, `update:users`
   - `read:actions`, `create:actions`, `update:actions`, `delete:actions`
   - `update:client_keys`
3. Copy the **Client ID** and **Client Secret**

The credentials-exchange Action does not use this application. The bootstrap creates a separate **Guardian Platform Actions** application for it, with only the `read:users` and `read:users_app_metadata` scopes, and rotates that application's secret with `update:client_keys` when the saved one is missing or a token request with it fails for any reason, including an Auth0 outage. The Action keeps the old secret until the run updates it, so if a re-run fails after rotating, re-run until it completes. Keep the bootstrap application to re-run the bootstrap later.

### 2. Create Pre-Bootstrap Secrets

```bash
# Bootstrap M2M credentials, plus the Auth Service API secret the post-login Action sends to Auth Service
kubectl create secret generic auth0-management \
  --from-literal=client-id=<bootstrap-client-id> \
  --from-literal=client-secret=<bootstrap-client-secret> \
  --from-literal=auth-service-api-secret=<auth-service-api-secret> \
  --namespace guardian

# Guardian admin user password
kubectl create secret generic platform-admin \
  --from-literal=password="$(openssl rand -base64 16)" \
  --namespace guardian
```

`<auth-service-api-secret>` must equal `global.secrets.authService.values.apiSecret` in the platform's `secrets.yaml`. If [guardctl](./guardctl.mdx) generated that file, use its value; otherwise generate one with `openssl rand -base64 32` and use it in both places. The bootstrap and the helper script stop before changing Auth0 when this key is missing while the post-login Action is enabled.

The bootstrap copies `auth-service-api-secret` into the post-login Action on each run, so after changing it, re-run the bootstrap.

### 3. Prepare the Bootstrap Values

From the deployment repository checkout, start from the example values file:

```bash
cp charts/auth0-bootstrap/examples/values.yaml bootstrap-values.yaml
```

Edit `bootstrap-values.yaml`, replacing the `CHANGE_ME` placeholders. `<domain>` is the Guardian Platform domain:

```yaml title="bootstrap-values.yaml"
auth0:
  domain: "<auth0-domain>" # No https:// or trailing slash
  api:
    identifier: "https://<domain>"

applications:
  frontend:
    callbacks:
      - "https://<domain>"
      - "http://localhost:5173"
    logoutUrls:
      - "https://<domain>"
      - "http://localhost:5173"
    webOrigins:
      - "https://<domain>"
      - "http://localhost:5173"

actions:
  postLogin:
    authService:
      url: "https://<domain>/authService"

users:
  admin:
    email: "<admin-email>"
```

The post-login Action sends the Auth Service API secret to Auth Service at `actions.postLogin.authService.url`. The bootstrap sets no environment metadata on the frontend application, so the Action treats it as `dev`: a non-empty `urlDev` takes precedence over `url`, and `urlStaging` and `urlProduction` are never used. Leave `urlDev` empty unless every sign-in should call that Auth Service. The chart fails to render when both `url` and `urlDev` are empty. A bootstrap file from [guardctl](./guardctl.mdx) sets only `url`.

### 4. Run the Bootstrap

The job mounts the Action sources from the `auth0-actions-source` ConfigMap:

```bash
kubectl create configmap auth0-actions-source \
  --from-file=scripts/auth0/actions/ \
  --namespace guardian \
  --dry-run=client -o yaml | kubectl apply -f -

helm upgrade --install auth0-bootstrap ./charts/auth0-bootstrap \
  --namespace guardian \
  --values bootstrap-values.yaml \
  --wait \
  --timeout 10m
```

Instead of these commands, the deployment repository's helper script checks the secrets named in the values file and the post-login Action's URL and API secret, refreshes the ConfigMap, runs the chart, and prints the job logs: `./scripts/auth0/bootstrap-auth0.sh -f bootstrap-values.yaml -n guardian`. It deletes the job afterwards and prints the command that reads the [generated credentials](#5-save-the-generated-credentials).

`helm` waits for the job to finish. From a second terminal, follow its logs:

```bash
kubectl logs job/auth0-bootstrap-auth0-bootstrap --namespace guardian -f
```

The job is idempotent - re-running the `helm upgrade` or the script sets the frontend application's callbacks, logout URLs, web origins, and grant types to the values, skips the other applications and users that already exist, and updates the API's scopes, the grants, and the Actions. Keep the frontend URLs in `bootstrap-values.yaml`: a re-run replaces any added in the Auth0 Dashboard.

### 5. Save the Generated Credentials

The job saves the client IDs and new client secrets to the `auth0-bootstrap-credentials` secret (`<release>-credentials`, or `credentialsSecret.name`), not to its logs. Read them with `jq`:

```bash
kubectl get secret auth0-bootstrap-credentials --namespace guardian -o json \
  | jq '.data | map_values(@base64d)'
```

| Key                                          | Value                                                                |
| -------------------------------------------- | -------------------------------------------------------------------- |
| `frontend-client-id`                         | Guardian Platform Frontend client ID                                 |
| `backend-client-id`, `backend-client-secret` | Guardian Platform Backend credentials                                |
| `worker-client-id`, `worker-client-secret`   | Governance Worker credentials                                        |
| `actions-client-id`, `actions-client-secret` | Guardian Platform Actions credentials, kept so later runs reuse them |
| `auth0-domain`                               | The tenant domain                                                    |

Helm creates the secret empty and keeps it on uninstall, and the job can only read and update it. Auth0 returns a client secret only when the application is created, so an application that already existed has only its client ID saved. If a secret is missing, copy or rotate it in the Auth0 Dashboard.

### 6. Create the Organization

The bootstrap does not create the Auth0 Organization that Studio sign-in requires. Create it before deploying the platform: the Governance Service links its database organization to the Auth0 Organization only when it creates it at startup. In the Auth0 Dashboard:

1. Under **Organizations**, create an organization named `guardian` (the `auth0.organizationName` value)
2. On its **Members** tab, add the admin user the bootstrap created
3. On its **Connections** tab, enable `Username-Password-Authentication`
4. Under **Applications** > **Guardian Platform Frontend** > **Login Experience**, set the type of users to **Business Users** and the login flow to **Prompt for Organization**

### 7. Update Chart Values

Fill in the [Helm Configuration](#helm-configuration) sections:

- `<auth0-domain>`: `auth0.domain` from `bootstrap-values.yaml`
- `https://<domain>`: `auth0.api.identifier`
- `<spa-client-id>`: `frontend-client-id`
- `platform-auth0` values: `backend-client-id` and `backend-client-secret`, for both the `clientId`/`clientSecret` and `mgmtClientId`/`mgmtClientSecret` pairs
- `governanceWorker` values: `worker-client-id` and `worker-client-secret`
- `<worker-encryption-key>` and `<jwt-secret>`: generate each with `openssl rand -base64 32`
- `<auth-service-api-secret>`: the `auth-service-api-secret` from step 2
- `<admin-email>`: `users.admin.email`

Read the `auth-service-api-secret` back with:

```bash
kubectl get secret auth0-management --namespace guardian \
  -o jsonpath='{.data.auth-service-api-secret}' | base64 -d
```

Then proceed to the [Helm Deployment guide](./helm-deployment.mdx). At startup the Governance Service copies the Auth0 Organization into the governance database, and the platform chart's post-install hook makes the admin its owner. If the governance organization already existed, the sync leaves its `idp_org_id` empty; set it to the Auth0 Organization ID (`org_...`) in the `organization` table, since restarting the service does not fill it.

## Alternative: Manual Setup via Auth0 CLI

Create the platform's Auth0 applications, API, organization, and Actions with the Auth0 CLI, in nine steps.

### 1. Install and Authenticate Auth0 CLI

Install the Auth0 CLI:

```bash
# macOS
brew install auth0/auth0-cli/auth0

# Linux
curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh
```

Authenticate with the Auth0 tenant:

```bash
auth0 login
```

Note the tenant domain shown after login (e.g. `your-tenant.us.auth0.com`).

Update `values.yaml` with the tenant domain.

`values.yaml` -> auth-service.config.idp:

```yaml
issuer: "https://<auth0-domain>/"
auth0:
  domain: "<auth0-domain>"
  managementAudience: "https://<auth0-domain>/api/v2/"
```

`values.yaml` -> governance-service.config:

```yaml
auth0Domain: "<auth0-domain>"
```

`values.yaml` -> guardian.config:

```yaml
auth0Domain: "<auth0-domain>"
```

`values.yaml` -> auth0:

```yaml
domain: "<auth0-domain>"
```

### 2. Create Platform API (M2M Application)

```bash
auth0 apps create \
  --name "EQTY Platform API" \
  --type m2m \
  --description "Backend API for Guardian Platform token validation" \
  --reveal-secrets
```

The output will look like:

```console
=== your-tenant.us.auth0.com application created

 CLIENT ID      abc123def456
 NAME           EQTY Platform API
 TYPE           Machine to Machine
 CLIENT SECRET  your-client-secret-here
```

Save both the Client ID and Client Secret.

The Governance Service uses these credentials to read Auth0 Organizations at startup, and fails to start without that access. Grant the Management API permission. Replace `<platform-api-client-id>` with the Client ID from above:

```bash
auth0 api post "client-grants" \
  --data '{
    "client_id": "<platform-api-client-id>",
    "audience": "https://<auth0-domain>/api/v2/",
    "scope": ["read:organizations"]
  }'
```

Update `secrets.yaml` with the Platform API credentials.

`secrets.yaml` -> global.secrets.auth.auth0.values:

```yaml
clientId: "<platform-api-client-id>"
clientSecret: "<platform-api-client-secret>"
```

### 3. Create Auth Service Backend (M2M Application)

```bash
auth0 apps create \
  --name "EQTY Auth Service Backend" \
  --type m2m \
  --description "User management for Guardian Platform" \
  --reveal-secrets
```

Save both the Client ID and Client Secret.

Grant the required Management API permissions. Replace `<auth-service-client-id>` with the Client ID from above:

```bash
auth0 api post "client-grants" \
  --data '{
    "client_id": "<auth-service-client-id>",
    "audience": "https://<auth0-domain>/api/v2/",
    "scope": [
      "read:users", "create:users", "update:users", "delete:users", "create:user_tickets",
      "read:organizations", "create:organizations", "update:organizations",
      "read:organization_members", "create:organization_members", "delete:organization_members",
      "update:clients"
    ]
  }'
```

Update `secrets.yaml` with the Auth Service Backend credentials.

`secrets.yaml` -> global.secrets.auth.auth0.values:

```yaml
mgmtClientId: "<auth-service-client-id>"
mgmtClientSecret: "<auth-service-client-secret>"
```

### 4. Create Guardian SPA

Replace `<domain>` with the Guardian Platform domain (e.g. `guardian.example.com`). Guardian returns to its own origin after sign-in, and `http://localhost:5173` is the local development server:

```bash
auth0 apps create \
  --name "Guardian Platform Frontend" \
  --type spa \
  --description "Frontend SPA for Guardian Platform" \
  --callbacks "https://<domain>,http://localhost:5173" \
  --logout-urls "https://<domain>,http://localhost:5173" \
  --web-origins "https://<domain>,http://localhost:5173" \
  --reveal-secrets
```

Save the Client ID from the output.

Update `values.yaml` with the SPA client ID.

`values.yaml` -> guardian.config:

```yaml
auth0ClientId: "<spa-client-id>"
```

### 5. Configure for Business Users (Organizations)

Enable organizations on the SPA to support multi-tenancy. Replace `<spa-client-id>` with the Client ID from step 4:

```bash
auth0 apps update <spa-client-id> \
  --organization-usage require \
  --organization-require-behavior "pre_login_prompt"
```

### 6. Create an API Definition

Replace `<domain>` with the Guardian Platform domain:

```bash
auth0 apis create \
  --name "Guardian Platform API" \
  --identifier "https://<domain>" \
  --scopes "governance:declarations:create,integrity:statements:create"
```

Update `values.yaml` with the API identifier. Guardian requests tokens for this API, and the Auth Service accepts them.

`values.yaml` -> auth-service.config.idp.auth0:

```yaml
apiIdentifier: "https://<domain>"
```

`values.yaml` -> guardian.config:

```yaml
auth0Audience: "https://<domain>"
```

### 7. Create Governance Worker (M2M Application)

The Governance Worker is the platform's service account for automated governance workflows.

```bash
auth0 apps create \
  --name "EQTY Governance Worker" \
  --type m2m \
  --description "Service account for Guardian Platform workflows" \
  --reveal-secrets
```

Save both the Client ID and Client Secret.

Authorize it on the API from step 6. Replace `<worker-client-id>` with the Client ID from above:

```bash
auth0 api post "client-grants" \
  --data '{
    "client_id": "<worker-client-id>",
    "audience": "https://<domain>",
    "scope": ["governance:declarations:create", "integrity:statements:create"]
  }'
```

Generate an encryption key for the worker:

```bash
openssl rand -base64 32
```

Update `secrets.yaml` with the worker credentials.

`secrets.yaml` -> global.secrets.governanceWorker.values:

```yaml
encryptionKey: "<generated-key>"
clientId: "<worker-client-id>"
clientSecret: "<worker-client-secret>"
```

### 8. Create the Organization and Platform Admin

Guardian sign-in requires an Auth0 Organization. Create one with the name set in `auth0.organizationName`:

```bash
auth0 api post "organizations" \
  --data '{"name": "guardian", "display_name": "Guardian Platform"}'
```

Save the `id` from the output (it starts with `org_`).

The platform admin must be a user in the tenant. Use an existing user, or create one in the Auth0 Dashboard under **User Management** > **Users**, and note its user ID (e.g. `auth0|...`). Add the user to the organization:

```bash
auth0 api post "organizations/<org-id>/members" \
  --data '{"members": ["<admin-user-id>"]}'
```

In the Auth0 Dashboard, on the organization's **Connections** tab, enable `Username-Password-Authentication` (or the connection the admin uses) so members can sign in.

Update `values.yaml` with the admin's email. The platform chart's post-install hook looks up this user and makes it the organization's owner.

`values.yaml` -> auth0:

```yaml
platformAdminEmail: "<admin-email>"
```

### 9. Deploy the Auth0 Actions

Two Actions in the deployment repository's `scripts/auth0/actions/` directory add the platform's organization, role, and service-account claims to tokens. The `auth0-bootstrap` chart creates, deploys, and binds both. To add them by hand, create each in the Auth0 Dashboard under **Actions** > **Library**, deploy it, and add it to its trigger:

| Action source                              | Trigger                                     | Secrets and dependencies                                                                                                               |
| ------------------------------------------ | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `post-login-users-and-service-accounts.js` | Login (`post-login`)                        | `AUTH_SERVICE_URL`: `https://<domain>/authService`; `AUTH_SERVICE_API_SECRET`: the `global.secrets.authService.values.apiSecret` value |
| `service-account-credentials.js`           | Machine to Machine (`credentials-exchange`) | `domain`: `<auth0-domain>`; `clientId` and `clientSecret`: an M2M application's credentials; dependency `auth0` version `3.x`          |

For `service-account-credentials.js`, create a separate M2M application named `Guardian Platform Actions`, authorized for the Auth0 Management API with only the `read:users` and `read:users_app_metadata` scopes, as the bootstrap does.

## Alternative: Web UI Setup

<details>
<summary>Click to expand Auth0 Dashboard instructions</summary>

### Using the Auth0 Dashboard

#### 1. Create Platform API Application

- Navigate to Applications > Applications in Auth0 Dashboard
- Click "Create Application"
- Name: "EQTY Platform API"
- Type: Machine to Machine Applications
- Authorize it to call the Auth0 Management API
- Grant scope: `read:organizations`
- Save the Client ID and Client Secret

Update `secrets.yaml` with the Platform API credentials.

`secrets.yaml` -> global.secrets.auth.auth0.values:

```yaml
clientId: "<platform-api-client-id>"
clientSecret: "<platform-api-client-secret>"
```

#### 2. Create Auth Service Backend Application

- Create another M2M application: "EQTY Auth Service Backend"
- Authorize it to call the Auth0 Management API
- Grant the scopes listed in [step 3](#3-create-auth-service-backend-m2m-application) of the CLI method
- Save the Client ID and Client Secret

Update `secrets.yaml` with the Auth Service Backend credentials.

`secrets.yaml` -> global.secrets.auth.auth0.values:

```yaml
mgmtClientId: "<auth-service-client-id>"
mgmtClientSecret: "<auth-service-client-secret>"
```

#### 3. Create Guardian SPA

- Create a Single Page Application: "Guardian Platform Frontend"
- Allowed Callback URLs, Allowed Logout URLs, and Allowed Web Origins: `https://<domain>, http://localhost:5173`
- Change the application's login experience to "Business Users"
- Save the Client ID

Update `values.yaml` with the domain and SPA client ID.

`values.yaml` -> auth-service.config.idp:

```yaml
issuer: "https://<auth0-domain>/"
auth0:
  domain: "<auth0-domain>"
  managementAudience: "https://<auth0-domain>/api/v2/"
```

`values.yaml` -> governance-service.config:

```yaml
auth0Domain: "<auth0-domain>"
```

`values.yaml` -> guardian.config:

```yaml
auth0Domain: "<auth0-domain>"
auth0ClientId: "<spa-client-id>"
```

#### 4. Create API Definition

- Navigate to Applications > APIs
- Create API with identifier: `https://<domain>`
- Add permissions: `governance:declarations:create`, `integrity:statements:create`

Update `values.yaml` with the API identifier.

`values.yaml` -> auth-service.config.idp.auth0:

```yaml
apiIdentifier: "https://<domain>"
```

`values.yaml` -> guardian.config:

```yaml
auth0Audience: "https://<domain>"
```

#### 5. Create Governance Worker Application

- Create another M2M application: "EQTY Governance Worker"
- Authorize it to call the API from step 4, with both of its permissions
- Save the Client ID and Client Secret
- Generate an encryption key: `openssl rand -base64 32`

Update `secrets.yaml` with the worker credentials.

`secrets.yaml` -> global.secrets.governanceWorker.values:

```yaml
encryptionKey: "<generated-key>"
clientId: "<worker-client-id>"
clientSecret: "<worker-client-secret>"
```

#### 6. Create the Organization and Actions

- Navigate to Organizations, create an organization named `guardian`, add the platform admin as a member, and enable `Username-Password-Authentication` on its Connections tab
- Set `auth0.platformAdminEmail` in `values.yaml` to the admin's email
- Deploy the two Actions as described in [step 9](#9-deploy-the-auth0-actions) of the CLI method

</details>

## Verification

Verify the OIDC discovery endpoint. The response's `issuer` field must equal `https://<auth0-domain>/`:

```bash
curl "https://<auth0-domain>/.well-known/openid-configuration"
```

Test token issuance with the Governance Worker credentials:

```bash
curl -X POST "https://<auth0-domain>/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "<worker-client-id>",
    "client_secret": "<worker-client-secret>",
    "audience": "https://<domain>",
    "grant_type": "client_credentials"
  }'
```

If the first command returns the discovery document and the second returns an `access_token`, the Auth0 configuration is correct.

## Security Best Practices

- **Rotate Secrets:** Regularly rotate client secrets, update the Kubernetes secrets, and restart Auth Service so it picks up the new Governance Worker secret
- **Least Privilege:** Grant only the Management API scopes this guide lists. Once a bootstrap run has completed with the Guardian Platform Actions application, no Action uses the bootstrap M2M application, so you can remove its scopes, and add them back before re-running the bootstrap. Until then, the credentials-exchange Action still uses it, and removing its scopes drops the service-account claims from Governance Worker tokens
- **Organizations:** Use Auth0 Organizations for tenant isolation in multi-tenant deployments
- **Monitor Activity:** Enable Auth0 log streaming to monitor authentication events and detect anomalies

## Troubleshooting

- **`Failed to get Management API token`** — Solution: Check the `auth0-management` credentials, that the bootstrap M2M is authorized for the Auth0 Management API, and that `auth0.domain` has no `https://` or trailing slash
- **Action fails with `HTTP 403` `insufficient_scope`** — Solution: Add the four `actions` scopes from quick-start [step 1](#1-create-the-bootstrap-m2m-application) to the bootstrap M2M and re-run
- **`Failed to prepare Actions application (HTTP 403)`** — Solution: Add `update:client_keys` to the bootstrap M2M and re-run; the bootstrap rotates the Guardian Platform Actions secret when the saved one is missing or a token request with it fails
- **`actions.postLogin.authService.url (or urlDev) is required`** — Solution: Set `actions.postLogin.authService.url` in `bootstrap-values.yaml`, as in [step 3](#3-prepare-the-bootstrap-values)
- **`The auth0-management Secret has no auth-service-api-secret key`** — Solution: Add the key with the Auth Service API secret, as in [step 2](#2-create-pre-bootstrap-secrets), and re-run
- **No client secret in the credentials secret** — Solution: The application already existed; copy or rotate its secret in the Auth0 Dashboard
- **`Failed to create user (HTTP 400)`** — Solution: The `platform-admin` password fails the tenant's password policy (**Authentication** > **Database** > **Username-Password-Authentication** > **Password Policy**); recreate the secret with a stronger password and re-run. If the tenant uses another database connection, set `users.admin.connection`

## Official Documentation

- [Auth0 CLI Documentation](https://github.com/auth0/auth0-cli)
- [Auth0 Management API Reference](https://auth0.com/docs/api/management/v2)
- [Auth0 Applications Overview](https://auth0.com/docs/get-started/applications)
- [Auth0 Organizations (Multi-tenancy)](https://auth0.com/docs/manage-users/organizations)
- [Auth0 Actions](https://auth0.com/docs/customize/actions)
- [Helm Chart Examples](https://github.com/eqtylab/deployment/tree/main/charts/guardian-platform/examples)

## Related

- [Authentication](./authentication.mdx) — how Auth0 compares with the other supported providers
- [Identity Providers](../auth-service/identity-providers.mdx) — what Auth Service supports in Auth0 mode
- [Chart Values](./chart-values.mdx) — the full values and secrets files these settings go into
- [Helm Deployment](./helm-deployment.mdx) — deploying the platform once the provider is configured