# Set Up ACP with Okta

Step-by-step guide to configuring Okta as your identity provider for ACP. Map groups, scp claims, and org context into the governance pipeline.

# Set Up ACP with Okta

This guide walks you through configuring Okta's authorization server to issue JWTs that ACP can verify and enforce.

---

## What you need

- An Okta organization (developer or production)
- An ACP Cloud workspace ([sign up](https://cloud.agenticcontrolplane.com/login?from=%2Fonboarding))

---

## Step 1: Create an authorization server

In the Okta Admin Console, go to **Security → API → Authorization Servers**.

You can use the default authorization server or create a custom one:

| Field | Value |
|-------|-------|
| Name | `ACP Gateway` |
| Audience | `https://api.agenticcontrolplane.com/your-slug` |
| Description | Authorization server for ACP-governed tools |

The audience must match what you configure in ACP. It appears as the `aud` claim in every JWT.

---

## Step 2: Add scopes

Under your authorization server, go to **Scopes → Add Scope**. Create scopes for each tool category:

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

For each scope:
- **Name**: The scope string (e.g. `salesforce:read`)
- **Include in public metadata**: Yes
- **Default scope**: No (require explicit request)

---

## Step 3: Create access policies

Go to **Access Policies → Add Policy** on your authorization server. Create a policy that applies to your application, then add rules:

| Rule | Scopes | Groups |
|------|--------|--------|
| Sales Read | `salesforce:read` | Sales Team |
| Sales Full | `salesforce:read`, `salesforce:write` | Sales Managers |
| Dev Access | `github:read`, `github:write`, `slack:read` | Engineering |
| Admin | All scopes | IT Admins |

Rules control which scopes a user can request based on their group membership.

---

## Step 4: Set up group claims

By default, Okta doesn't include groups in access tokens. Add a claim:

1. Go to your authorization server's **Claims** tab
2. Click **Add Claim**

| Field | Value |
|-------|-------|
| Name | `groups` |
| Include in token type | Access Token |
| Value type | Groups |
| Filter | Matches regex `.*` (or filter to specific groups) |
| Include in | Any scope |

This adds the user's Okta groups to their JWT, which ACP can use for role-based governance.

---

## Step 5: Configure ACP

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

| Field | Value |
|-------|-------|
| Issuer | `https://your-org.okta.com/oauth2/your-auth-server-id` |
| Audience | `https://api.agenticcontrolplane.com/your-slug` |
| JWKS URI | Leave blank (auto-discovered from issuer) |
| Scope Claim | `scp` |
| Role Claim | `groups` |
| Tenant Claim | (optional — see multi-tenant section below) |

### Okta claim mapping

Okta uses different claim names than Auth0. Here's how they map to ACP:

| Okta Claim | ACP Field | Example |
|------------|-----------|---------|
| `sub` | `identity.sub` | `00u1a2b3c4d5e6f7g8` |
| `iss` | `identity.issuer` | `https://your-org.okta.com/oauth2/default` |
| `scp` | `identity.scopes` | `["openid", "salesforce:read"]` |
| `groups` | `identity.roles` | `["Sales Team", "Engineering"]` |
| `email` | `identity.email` | `alice@acme.com` |
| `name` | `identity.name` | `Alice Chen` |

Note: Okta uses `scp` (array) for scopes, while Auth0 uses `scope` (space-delimited string). ACP normalizes both formats.

---

## Step 6: Configure tool scopes

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

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

When a user calls a tool, ACP checks their JWT's `scp` claim against the required scopes. Missing scopes return `403 Insufficient scope`.

---

## Multi-tenant with Okta

If you manage multiple organizations, you can add a custom claim to carry the tenant context:

1. Add a custom user attribute in **Directory → Profile Editor** (e.g. `tenant_id`)
2. Add a claim to your authorization server that maps to this attribute

Set the **Tenant Claim** in ACP to match your claim name. ACP uses this for tenant isolation — users in one tenant can't see another tenant's data.

---

## Troubleshooting

**"Invalid token: unexpected iss claim"**
Okta authorization server URLs include the server ID: `https://your-org.okta.com/oauth2/aus1234567`. Make sure the issuer in ACP matches exactly — including whether you're using the default server (`/oauth2/default`) or a custom one.

**"Insufficient scope"**
The user's JWT doesn't include the required scope. Check: (1) the scope exists on the authorization server, (2) the access policy rule grants that scope to the user's group, (3) the client is requesting the scope during authentication.

**"Groups claim missing"**
You need to explicitly add a groups claim to your authorization server (Step 4). Okta doesn't include groups by default.

**"Token expired"**
Okta's default access token lifetime is 1 hour. You can adjust this in your access policy rules under **Token Lifetime**.

---

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