# Agent Authorization Integration

ZeroID and Agent Authorisation (Shield) solve two distinct problems in agentic systems. ZeroID answers who the agent is. Shield answers what the agent is allowed to do at runtime. Using them together gives you a complete security model: cryptographically verified identity feeding policy-driven action enforcement.

### The Two-Layer Model

These two systems operate at different points in the request lifecycle.

**ZeroID — identity layer**

ZeroID issues and verifies JWTs that describe the agent's identity, trust level, delegation chain, and authorized scopes. It answers questions about provenance: who is this principal, how far has authority traveled, and who originally granted it? This work happens before the request reaches your service.

**Shield — runtime action layer**

Shield evaluates the action being attempted against Cedar policies and detector signals. It decides whether the specific action — sending a prompt, executing a tool, writing a file — is allowed given the current context. It can incorporate ZeroID claims as Cedar context, which means identity attributes directly influence runtime decisions.

The split matters because ZeroID controls what tokens can be issued and to whom, while Shield controls what a holder of a valid token is permitted to do with it. Neither system alone gives you both.

### Request Flow

The standard flow when both systems are in use:

1. The agent authenticates with ZeroID and receives a JWT access token.
2. The agent calls a downstream service, attaching the JWT as a bearer token.
3. The service verifies the JWT locally using ZeroID's JWKS.
4. The service extracts identity claims from the verified token.
5. The service passes those claims as context to Shield for guardrail evaluation.
6. Shield evaluates the action against Cedar policies and detector signals.
7. The service allows or denies the action based on Shield's decision.

ZeroID verification and Shield evaluation happen in sequence. If the JWT is invalid, the request is rejected before Shield is ever called. If the JWT is valid but Shield denies the action, the request is rejected at the guardrail layer.

### What ZeroID Provides to Shield Decisions

The claims in a ZeroID JWT can be passed directly as context to Shield's Cedar policies. This is how identity characteristics influence runtime action decisions without rebuilding identity logic inside Shield.

<table><thead><tr><th width="200">Claim</th><th>What It Tells Shield</th></tr></thead><tbody><tr><td><code>trust_level</code></td><td>How much confidence the platform has in this identity (<code>first_party</code>, <code>verified_third_party</code>, <code>unverified</code>). Use it to gate sensitive operations.</td></tr><tr><td><code>sub_type</code></td><td>The operational role of the agent (<code>orchestrator</code>, <code>tool_agent</code>, <code>code_agent</code>, <code>autonomous</code>, etc.). Use it to apply different enforcement thresholds per agent type.</td></tr><tr><td><code>delegation_depth</code></td><td>How many hops the token has traveled from the original authority. Use it to reject deeply delegated tokens for high-risk operations.</td></tr><tr><td><code>scopes</code></td><td>What the token is authorized for. Use it to confirm the agent has the right scope for the action, independent of Cedar policy.</td></tr><tr><td><code>act.sub</code></td><td>The identity that delegated authority to the current principal. Use it for audit context and to require a known orchestrator be present in the chain.</td></tr></tbody></table>

### Integration Pattern

The pattern has three steps: verify the token, extract claims, pass them to Shield.

#### Python

```python
from highflame.zeroid import ZeroIDClient
from highflame import Highflame, GuardRequest

zeroid = ZeroIDClient(
    base_url="https://auth.zeroid.dev",
    account_id="acct-demo",
    project_id="proj-prod",
)

shield = Highflame(api_key="hf_sk_...")


def handle_request(authorization_header: str, prompt: str, session_id: str):
    # Step 1: Verify the ZeroID JWT
    identity = zeroid.tokens.verify_bearer(authorization_header)

    # Step 2: Extract claims
    trust_level = identity.trust_level        # "first_party" | "verified_third_party" | "unverified"
    sub_type = identity.sub_type              # "orchestrator" | "tool_agent" | "code_agent" | ...
    delegation_depth = identity.delegation_depth  # int
    delegated_by = identity.delegated_by()   # orchestrator sub, or None

    # Step 3: Evaluate the action with Shield, passing identity context
    resp = shield.guard.evaluate(GuardRequest(
        content=prompt,
        content_type="prompt",
        action="process_prompt",
        session_id=session_id,
        # Pass ZeroID claims as additional context for Cedar policies
        context={
            "trust_level": trust_level,
            "sub_type": sub_type,
            "delegation_depth": delegation_depth,
            "delegated_by": delegated_by,
            "scopes": identity.scopes,
        },
    ))

    # Step 4: Make the final decision
    if resp.denied:
        raise PermissionError(f"Request blocked: {resp.policy_reason}")

    return run_llm(prompt)
```

For async services:

```python
async def handle_request_async(authorization_header: str, prompt: str, session_id: str):
    identity = await zeroid.tokens.averify_bearer(authorization_header)

    resp = await shield.guard.aevaluate(GuardRequest(
        content=prompt,
        content_type="prompt",
        action="process_prompt",
        session_id=session_id,
        context={
            "trust_level": identity.trust_level,
            "sub_type": identity.sub_type,
            "delegation_depth": identity.delegation_depth,
            "delegated_by": identity.delegated_by(),
            "scopes": identity.scopes,
        },
    ))

    if resp.denied:
        raise PermissionError(f"Request blocked: {resp.policy_reason}")

    return await run_llm_async(prompt)
```

Helper methods on `ZeroIDIdentity` that are useful before calling Shield:

```python
identity.has_scope("data:read")   # bool — confirm scope before calling Shield
identity.is_delegated()           # bool — True if act.sub is present
identity.delegated_by()           # str | None — the orchestrator sub
```

#### TypeScript

```typescript
import { ZeroIDClient } from "@highflame/sdk";
import { Highflame } from "@highflame/sdk";

const zeroid = new ZeroIDClient({
  baseUrl: "https://auth.zeroid.dev",
  accountId: "acct-demo",
  projectId: "proj-prod",
});

const shield = new Highflame({ apiKey: "hf_sk_..." });

async function handleRequest(
  authorizationHeader: string,
  prompt: string,
  sessionId: string,
) {
  // Step 1: Verify the ZeroID JWT
  const identity = await zeroid.tokens.verifyBearer(authorizationHeader);

  // Step 2: Extract claims
  const { trust_level, sub_type, delegation_depth, scopes } = identity;
  const delegatedBy = identity.delegatedBy();

  // Step 3: Evaluate the action with Shield
  const resp = await shield.guard.evaluate({
    content: prompt,
    content_type: "prompt",
    action: "process_prompt",
    session_id: sessionId,
    // Pass ZeroID claims as additional context for Cedar policies
    context: {
      trust_level,
      sub_type,
      delegation_depth,
      delegated_by: delegatedBy,
      scopes,
    },
  });

  // Step 4: Make the final decision
  if (resp.decision === "deny") {
    throw new Error(`Request blocked: ${resp.policy_reason}`);
  }

  return runLLM(prompt);
}
```

Helper methods on the TypeScript `ZeroIDIdentity`:

```typescript
identity.hasScope("data:read");   // boolean
identity.isDelegated();           // boolean — true if act.sub is present
identity.delegatedBy();           // string | undefined
```

### Cedar Policy Examples

These policies show how to use ZeroID claims in Shield's Cedar enforcement layer. Cedar evaluates the context object your service passes to Shield alongside the detector signals Shield produces.

#### Block tool agents with delegation depth greater than one

```cedar
permit (
  principal,
  action == Action::"call_tool",
  resource
)
when {
  context.sub_type != "tool_agent" ||
  context.delegation_depth <= 1
};
```

This allows tool agents only when they are at most one hop from the original authority. Any tool agent token that has been delegated more than once is blocked.

#### Require first-party trust for sensitive operations

```cedar
permit (
  principal,
  action == Action::"write_file",
  resource
)
when {
  context.trust_level == "first_party"
};
```

Write operations are blocked for any identity that is not explicitly marked `first_party`. Verified third-party and unverified agents cannot write.

#### Deny unverified identities from all write operations

```cedar
forbid (
  principal,
  action in [Action::"write_file", Action::"call_tool"],
  resource
)
when {
  context.trust_level == "unverified"
};
```

This is a baseline deny rule. Unverified agents are blocked from any action with side effects regardless of other policies.

#### Require a known orchestrator in the delegation chain

```cedar
permit (
  principal,
  action == Action::"call_tool",
  resource
)
when {
  context.sub_type != "tool_agent" ||
  (
    context.sub_type == "tool_agent" &&
    context.delegated_by like "spiffe://zeroid.dev/acct-demo/proj-prod/agent/*"
  )
};
```

Tool agents must have been delegated authority by a known orchestrator in the same project. Tool agents that arrived without a delegation chain or from an unexpected source are blocked.

#### Combine trust level and sub type for tiered access

```cedar
permit (
  principal,
  action == Action::"process_prompt",
  resource
)
when {
  (context.trust_level == "first_party") ||
  (context.trust_level == "verified_third_party" && context.sub_type == "chatbot") ||
  (context.trust_level == "verified_third_party" && context.sub_type == "assistant")
};
```

First-party agents get full access. Verified third-party agents can only act if their sub type is `chatbot` or `assistant`. All other combinations are denied by default.

### When to Use ZeroID Alone, Shield Alone, or Both

**ZeroID alone** is sufficient when:

* you need to authenticate an agent and verify its delegation chain
* your authorization requirements are fully expressed in scopes
* you are building an internal service that trusts all identities issued by your ZeroID instance equally
* latency is critical and you want to keep authorization in the token without an additional network call

**Shield alone** is sufficient when:

* you are running guardrails on user-facing input or LLM output with no agent identity context
* your service uses service keys or API keys that do not carry identity claims
* you want runtime content safety and injection detection without modeling the identity layer

**Both together** when:

* you want policy decisions that incorporate agent identity, trust level, delegation depth, or sub type
* you are building multi-agent systems where different sub types face different runtime constraints
* you need an audit trail that links guardrail decisions back to a specific registered agent identity
* you are enforcing least-privilege at both the credential layer (what the token can do) and the runtime layer (what the action is allowed to attempt)

The typical production pattern for agentic platforms is to use both. ZeroID controls token issuance and delegation. Shield controls what happens at runtime. The claims ZeroID embeds in the JWT become the identity context that Cedar policies in Shield operate on.

#### What's Next?

* Read [**Downstream Authorization**](/agent-identity-zeroid/guides/downstream-authorization.md) for the full pattern of verifying ZeroID JWTs in your services before calling Shield.
* Read [**Agent Delegation**](/agent-identity-zeroid/guides/agent-delegation.md) to understand how `delegation_depth` and `act.sub` are populated in delegated tokens.
* Read [**Credential Policies**](/agent-identity-zeroid/guides/credential-policies.md) to control which grant types and delegation depths are allowed at issuance time, before runtime enforcement.
* Read the [**Shield Python SDK**](https://github.com/highflame-ai/highflame-docs/blob/main/api-reference/sdk/shield/python-sdk.md) or [**Shield TypeScript SDK**](https://github.com/highflame-ai/highflame-docs/blob/main/api-reference/sdk/shield/typescript-sdk.md) for full guard evaluation API reference.
* Read the [**ZeroID Python SDK**](https://github.com/highflame-ai/highflame-docs/blob/main/api-reference/sdk/zeroid/python-sdk.md) or [**ZeroID TypeScript SDK**](https://github.com/highflame-ai/highflame-docs/blob/main/api-reference/sdk/zeroid/typescript-sdk.md) for token verification API reference.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.highflame.ai/agent-identity-zeroid/guides/shield-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
