Skip to main content

Proxy RBAC & Cloud Auth

The proxy enforces role-based access control using policies embedded in JWT tokens from the Quint auth service. Evaluation is deny-first — every action must pass all checks to be allowed.

Token Types

Quint uses 6 token types, each identified by a prefix:
PrefixTypePurpose
qt_app_appApplication-level access
qt_bearer_bearerEnvironment-scoped access (has env field)
qt_agent_agentAgent identity with RBAC policy
qt_subagent_subagentChild agent with narrowed permissions
qt_session_sessionTime/event-limited session
qt_override_overrideOne-time decision override for a specific event
All tokens are ES256 (ECDSA P-256) JWTs. The proxy validates signatures against the auth service’s public key, which is fetched and cached with a configurable TTL (default: 5 minutes).

Deny-First Evaluation

Every action goes through 6 sequential checks. The first failure stops evaluation.
1

Step 1: Denied Actions

If the action matches any pattern in denied_actionsDENY.
2

Step 2: Allowed Actions

If allowed_actions is non-empty and the action matches none → DENY.
3

Step 3: Denied Resources

If the resource matches any pattern in denied_resourcesDENY.
4

Step 4: Allowed Resources

If allowed_resources is non-empty and the resource matches none → DENY.
5

Step 5: Sensitivity Level

If the resource’s sensitivity level exceeds the policy’s limit → DENY.
6

Step 6: Allowed

All checks passed → ALLOW.

Glob Pattern Matching

Actions and resources are matched using glob patterns with colon-aware wildcards:
PatternMatchesDoes Not Match
mcp:github:*mcp:github:list_repos.listmcp:slack:post.send
mcp:**mcp:github:list_repos.listhttp:api.openai.com:POST.chat
mcp:*:*.readmcp:postgres:query.readmcp:postgres:query.write
*:*:*.deletemcp:s3:remove_object.deletemcp:s3:list_objects.list
  • * matches within a single colon-separated segment
  • ** matches across segments (recursive)

RBAC Policy Structure

Each agent/subagent token carries an RBAC policy in its JWT claims:
{
  "sub": "customer-uuid",
  "typ": "agent",
  "agent_id": "support-bot",
  "rbac": {
    "allowed_actions": ["mcp:slack:*", "mcp:notion:*"],
    "denied_actions": ["mcp:**:*.delete", "mcp:**:*.execute"],
    "allowed_resources": ["*"],
    "denied_resources": ["vault/*", "*/credentials"],
    "sensitivity_level": 2,
    "max_risk_score": 75
  }
}
FieldTypeDescription
allowed_actionsstring[]Glob patterns for permitted actions (empty = allow all)
denied_actionsstring[]Glob patterns for blocked actions (checked first)
allowed_resourcesstring[]Glob patterns for permitted resources
denied_resourcesstring[]Glob patterns for blocked resources
sensitivity_levelintMax data sensitivity the agent can access (0-4)
max_risk_scoreintMax risk score before blocking (0-100)

Subagent Policy Narrowing

When a parent agent spawns a child, the child’s RBAC policy is automatically narrowed — it can never exceed the parent’s permissions:
ConstraintRule
Allowed actionschild ⊆ parent (intersection)
Denied actionschild ⊇ parent (union — child inherits all parent denials)
Sensitivity levelchild ≤ parent (minimum)
Max risk scorechild ≤ parent (minimum)
Parent: allowed_actions = ["mcp:github:*", "mcp:slack:*"]
Child:  allowed_actions = ["mcp:github:*.read"]
Result: valid (child is a subset)

Parent: denied_actions = ["mcp:**:*.delete"]
Child:  denied_actions = ["mcp:**:*.delete", "mcp:**:*.execute"]
Result: valid (child is a superset)

Parent: sensitivity_level = 3
Child:  sensitivity_level = 4
Result: INVALID (child exceeds parent)
Narrowing is validated cryptographically — a subagent token with wider permissions than its parent will be rejected during JWT validation.

Local Scope Hierarchy

For agents without cloud tokens, the proxy uses a local scope system:
ScopeImplies
tools:admintools:write, tools:read
tools:executetools:read
tools:writetools:read
tools:read(base level)
Tool names are mapped to required scopes:
Tool Prefix/KeywordRequired Scope
delete, remove, droptools:admin
execute, shell, bash, runtools:execute
write, create, update, edittools:write
read, get, list, searchtools:read
Unknowntools:write (fail-closed)

Cloud Key Validation

The proxy fetches the auth service’s public key to validate JWT signatures:
GET {auth_service_url}/keys/public/{customer_id}
SettingDefaultDescription
base_urlAuth service URL
customer_idCustomer ID for key lookup
timeout_ms5000Validation timeout
key_refresh_seconds300Public key cache TTL
{
  "auth_service": {
    "base_url": "https://auth.quintai.com",
    "customer_id": "a1b2c3d4",
    "enabled": true,
    "timeout_ms": 5000,
    "key_refresh_seconds": 300
  }
}
Environment variable QUINT_TOKEN can provide a cloud JWT token for stdio relay mode.

Token Resolution Flow