# Apply OPA policies to your gateway and surfaces

> Create OPA Rego policy definitions and apply them at gateway scope or surface scope to control which requests the Agent Gateway allows or forwards.
By the end of this guide, you will have OPA Rego policies active at gateway scope (all surfaces) or at individual surface scope (one surface only).

A policy definition is a named, reusable block of Rego that the gateway evaluates before forwarding a request. You create the definition once in Policies, then attach it to a gateway or surface. For background on how the gateway evaluates policies, see [OPA policies](/products/affinidi-trust-fabric/agent-gateway/concepts/opa-policies.md).

Without a policy, the gateway forwards every authenticated request without evaluating its content or origin. Authentication confirms who is calling. A policy decides what they are allowed to do.

Use this guide when:

- You need a single access-control rule that applies to every surface on a gateway.

- You need per-surface access control that differs from your gateway-wide rule.

- You need to restrict traffic by JWT claims, caller identity, HTTP method, or surface name.

You do not need a policy if authentication alone is sufficient. A Caller Context element handles credential enforcement without Rego.

## Prerequisites

- A running Agent Gateway instance with the dashboard accessible.

- Administrator role on the gateway.

- At least one surface for surface-scoped policies. See [A2A surface starter](/products/affinidi-trust-fabric/agent-gateway/how-to-guides/setup/a2a-surface-starter.md) or [MCP surface starter](/products/affinidi-trust-fabric/agent-gateway/how-to-guides/setup/mcp-surface-starter.md) to create one.

- Familiarity with [OPA Rego syntax](https://www.openpolicyagent.org/docs/latest/policy-language/). Test your Rego logic at [play.openpolicyagent.org](https://play.openpolicyagent.org/) before saving to the gateway.

## Policy scopes

The gateway evaluates policies in order: gateway policy first, then surface policy. A request denied at gateway scope never reaches surface-level evaluation.

| Scope | Package declaration | Attached at | Applies to |
| Gateway | package gateway.policy | Gateway → Global Policy tab | Every request on this gateway |
| Surface | package surface.policy | Surface canvas → Policy element | Requests to one surface only |

Surface policies also support additional scopes (access point, target, response, and MCP tool), configured directly in the surface editor. See [Use JWT claims to control access to a surface](/products/affinidi-trust-fabric/agent-gateway/how-to-guides/policies/use-jwt-claims-to-control-access-to-a-surface.md) for surface-level policy placement.

## Steps

Create a policy definition

All policies are created in Policies before being attached to a gateway or surface.

- 
In the sidebar, select Policies.

- 
Select the Gateway tab for a gateway-scoped policy, or the Agent Surfaces tab for a surface-scoped policy.

- 
Select Define Gateway Policy or Define Agent Surface Policy.

- 
Fill in the policy fields:

| Field | Required | Description |
| Name | Yes | A descriptive label, for example Require authentication or Admin only. |
| Description | No | Free-text explanation of what the policy enforces. |
| Type | Yes | Gateway for gateway-wide enforcement; Agent Surfaces for per-surface enforcement. Pre-set by which button you selected. |
| Enabled | Yes | When checked, the policy is evaluated on every matching request. Uncheck to save the definition without activating it. |

- 
Write the Rego in the Policy Content (Rego) editor. Use the correct package declaration for the scope:

```rego
# Gateway-scoped policy
package gateway.policy

default allow = false

allow if {
  input.source_auth.subject
}
```

```rego
# Surface-scoped policy
package surface.policy

default allow = false

allow if {
  input.source_auth.subject
}
```

The editor validates Rego syntax as you type. A green Valid indicator confirms the syntax before you save.

Tip

Start with default allow = false and explicitly allow only the conditions you need. A default of true allows all traffic, including unauthenticated requests, if no rule matches.

Caution

A misconfigured gateway policy blocks all traffic to every surface. Test your policy logic at [play.openpolicyagent.org](https://play.openpolicyagent.org/) before saving to production.

For the complete field reference for input, see [OPA policy input reference](/products/affinidi-trust-fabric/agent-gateway/reference/surfaces/policy-input.md).

- Select Create. The policy appears in the list with Enabled or Disabled status.

### Common policy patterns

Restricting access to admin users only:

```rego
package surface.policy

default allow = false

allow if {
  input.source_auth.claims.role == "admin"
}
```

Allowing only POST requests:

```rego
package surface.policy

default allow = false

allow if {
  input.http.method == "POST"
}
```

Branching rules by surface name:

```rego
package surface.policy

default allow = false

allow if {
  input.channel.name == "public-mcp"
}

allow if {
  input.channel.name == "private-mcp"
  input.source_auth.subject
}
```

Apply to a gateway

Apply a gateway policy to enforce a rule on every surface on that gateway.

- In the sidebar, select Gateways, then open the gateway to configure.

- Select the Global Policy tab.

- Switch the toggle to Enabled.

- Select your policy from the Select Gateway Policy dropdown. Only enabled definitions of type Gateway appear.

- Select Save Policy.

The policy takes effect on the next incoming request.

Apply to a surface

Apply a surface policy to enforce a rule on one specific surface only.

- In the sidebar, select Surfaces, then open the surface to configure.

- In the left palette, find Policy under the Security & Policy category.

- Drag Policy onto the canvas and drop it on the arrow where you want the rule evaluated, typically the arrow leaving the Access Point to gate all inbound requests before further processing.

- Select the Policy element to open its config panel. In the Policy Definition dropdown, select the definition you created in Step 1. Only enabled definitions of type Agent Surfaces appear.

- Select the Save changes button (the blue disk icon in the toolbar) or press Cmd+S (macOS) / Ctrl+S (Windows/Linux).

Only requests routed to this surface are evaluated by the surface policy. Other surfaces are unaffected.

## Manage policy definitions

### Enable or disable a policy

- In the sidebar, select Policies.

- Select the policy name or the edit button to open the policy editor.

- Check or uncheck the Enabled checkbox and select Save.

The change takes effect immediately. Disabling a policy that is attached to a gateway or surface suspends enforcement without removing the attachment.

### Delete a policy

- In the sidebar, select Policies.

- Select the delete icon on the policy row and confirm the deletion.

Deletion is permanent. Confirm no active gateway or surface references the policy before deleting.

## Confirm

### Test 1: blocked request returns 403

Send a request that does not satisfy the policy’s allow conditions. For a policy that requires input.source_auth.subject, send without credentials:

```bash
curl -k -X POST "https://" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"message/send","params":{}}'
```

Expected: 403 Forbidden. The policy evaluated allow = false and the gateway rejected the request.

The -k flag disables TLS certificate verification. Use this for local testing only. Remove it in production.

### Test 2: allowed request is forwarded

Send a request that satisfies the policy conditions, for example a valid Authorization: Bearer header:

```bash
curl -k -X POST "https://" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer " \
  -d '{"jsonrpc":"2.0","id":1,"method":"message/send","params":{}}'
```

Expected: the gateway forwards the request. Open Monitoring → Logs to confirm the policy decision event for each request.

The -k flag disables TLS certificate verification. Use this for local testing only. Remove it in production.

## Troubleshooting

| Symptom | Likely cause | Fix |
| All requests are blocked after saving the policy. | default allow = false matches before any explicit allow rule fires. | Re-check your allow conditions. Validate the Rego logic at [play.openpolicyagent.org](https://play.openpolicyagent.org/) against realistic input values. |
| Policy changes have no effect. | Policy is disabled, uses the wrong package declaration, or is not attached to the gateway or surface. | Confirm the Enabled checkbox is checked, the package matches the scope (gateway.policy or surface.policy), and the policy is selected in the gateway or surface editor. |
| 403 only on some surfaces. | A surface policy differs from the gateway policy, or one surface has no policy while another does. | Review both gateway-level and surface-level policies for each affected surface. |
| input.source_auth is empty in policy evaluation. | Source auth is not enabled on the surface, or the request carries no credentials. | Enable source authentication on the surface or send valid credentials. |
| Rego editor shows a validation error and will not save. | Syntax error in the policy. | Validate the policy at [play.openpolicyagent.org](https://play.openpolicyagent.org/) and paste the corrected Rego. |
| Policy definition does not appear in the gateway or surface dropdown. | The definition is disabled or uses the wrong type. | Confirm the definition is enabled and the type matches the attachment point (Gateway or Agent Surfaces). |
| Policy is saved with status disabled. | The Enabled checkbox was unchecked at creation time. | Open the policy, check Enabled, and select Save. |

## Next steps

- [Restrict surface access with API key authentication](/products/affinidi-trust-fabric/agent-gateway/how-to-guides/access/restrict-surface-access-with-api-key.md): add a Caller Context element to authenticate callers before policies evaluate.

- [Limit surface access by agent identity](/products/affinidi-trust-fabric/agent-gateway/how-to-guides/access/limit-surface-access-by-agent-identity.md): derive a stable agent DID and write DID-based policy rules.

## Related

- [OPA policies](/products/affinidi-trust-fabric/agent-gateway/concepts/opa-policies.md): complete input context reference and evaluation model.

- [Surfaces](/products/affinidi-trust-fabric/agent-gateway/concepts/surfaces.md): conceptual model for how policy scopes attach to runtime surfaces.

- [OPA policy input](/products/affinidi-trust-fabric/agent-gateway/reference/surfaces/policy-input.md): field reference for all input fields available in gateway, surface, and MCP tool policy scopes.
