# Set Up ACP with Auth0

Step-by-step guide to configuring Auth0 as your identity provider for ACP. Map scopes, permissions, roles, and org_id into the governance pipeline.

# Set Up ACP with Auth0

This guide walks you through the complete Auth0 setup — from creating the Auth0 API to seeing verified identity flow through your first tool call.

---

## What you need

- An Auth0 account (free tier works)
- An ACP Cloud workspace ([sign up](https://cloud.agenticcontrolplane.com/login?from=%2Fonboarding))

---

## Step 1: Create an Auth0 API

In the Auth0 Dashboard, go to **Applications → APIs → Create API**.

| Field | Value |
|-------|-------|
| Name | `ACP Gateway` (or anything descriptive) |
| Identifier (Audience) | `https://api.agenticcontrolplane.com/your-slug` |
| Signing Algorithm | **RS256** (required — ACP rejects HS256) |

The identifier becomes the `aud` claim in JWTs. ACP verifies it on every request.

---

## Step 2: Configure permissions

Under your API's **Permissions** tab, add the scopes your tools will require:

```
salesforce:read
salesforce:write
github:read
github:write
slack:read
slack:write
```

These will appear in the `permissions` claim of Auth0 JWTs when you enable RBAC.

### Enable RBAC

Go to your API's **Settings** tab and enable:
- **Enable RBAC** ✓
- **Add Permissions in the Access Token** ✓

Now when users authenticate, their JWT includes a `permissions` array with the scopes you've assigned to their role.

---

## Step 3: Set up roles

Go to **User Management → Roles** and create roles that map to your team structure:

| Role | Permissions |
|------|-------------|
| Sales (Read Only) | `salesforce:read` |
| Sales (Full Access) | `salesforce:read`, `salesforce:write` |
| Developer | `github:read`, `github:write`, `slack:read` |
| Admin | All permissions |

Assign users to roles. When they authenticate, their JWT carries their role's permissions.

---

## Step 4: Configure ACP

In your ACP dashboard, go to **Settings → Identity Providers** and enter:

| Field | Value |
|-------|-------|
| Issuer | `https://your-tenant.auth0.com/` |
| Audience | `https://api.agenticcontrolplane.com/your-slug` |
| JWKS URI | Leave blank (auto-discovered from issuer) |
| Scope Claim | `scope` |
| Role Claim | `permissions` |
| Tenant Claim | `org_id` |

### Auth0 claim mapping

Here's how Auth0 JWT claims map to ACP identity fields:

| Auth0 Claim | ACP Field | Example |
|-------------|-----------|---------|
| `sub` | `identity.sub` | `auth0\|8f3a2b1c9d4e5f6a` |
| `iss` | `identity.issuer` | `https://your-tenant.auth0.com/` |
| `scope` | `identity.scopes` | `["openid", "profile", "email"]` |
| `permissions` | `identity.roles` | `["salesforce:read", "github:write"]` |
| `org_id` | `identity.tenantId` | `org_acme_corp` |
| `email` | `identity.email` | `alice@acme.com` |
| `name` | `identity.name` | `Alice Chen` |

The `permissions` claim from Auth0 RBAC maps to roles in ACP. The `scope` claim carries OAuth scopes (if using custom grant flows). Both are checked during governance.

---

## Step 5: Configure tool scopes

In **Policies → Tool Scopes**, map permissions to tools:

```json
{
  "salesforce.query": ["salesforce:read"],
  "salesforce.createRecord": ["salesforce:write"],
  "github.listRepos": ["github:read"],
  "github.createIssue": ["github:write"]
}
```

When a user calls `salesforce.query`, ACP checks that their JWT contains `salesforce:read` in the `permissions` claim. If it doesn't, the call is rejected with `403 Insufficient scope`.

---

## Step 6: Test the flow

### Using the ACP playground

Go to **Tools → Playground** in the dashboard. Select a tool, enter test input, and execute. The playground uses your Firebase Auth session — you'll see the governance decision in real-time.

### Using an MCP client

Point Claude Desktop or any MCP client at `https://api.agenticcontrolplane.com/your-slug`. When you authenticate, Auth0 issues a JWT. ACP verifies it and grants access based on your permissions.

### Verify in the audit log

Check **Logs** in the dashboard. You'll see:

```json
{
  "sub": "auth0|8f3a2b1c9d4e5f6a",
  "tool": "salesforce.query",
  "scopes": ["salesforce:read", "salesforce:write"],
  "ok": true,
  "latencyMs": 142
}
```

The `sub` is the Auth0 user ID. The scopes are from the JWT. The action is fully attributed.

---

## Auth0 Organizations (multi-tenant)

If you use Auth0 Organizations, users' JWTs include an `org_id` claim. Set the **Tenant Claim** to `org_id` in ACP's IdP config.

ACP uses this for tenant isolation — users in one organization can't access another organization's data, even if they authenticate with the same Auth0 tenant.

---

## Troubleshooting

**"Invalid token: unexpected iss claim"**
Your issuer URL has a trailing slash mismatch. Auth0 tokens use `https://your-tenant.auth0.com/` (with trailing slash). ACP normalizes this, but make sure your configured issuer matches what Auth0 puts in the token.

**"Insufficient scope"**
The user's JWT doesn't include the required permission. Check: (1) RBAC is enabled on the API, (2) "Add Permissions in the Access Token" is checked, (3) the user is assigned a role with the required permission.

**"Missing bearer token"**
The MCP client isn't sending the Authorization header. Ensure the client is configured to use OAuth, not just connecting without auth.

---

[Back to guides](/guides/) · [Set up Okta →](/guides/okta/) · [Set up Entra ID →](/guides/entra-id/)
