Skip to content
API Reference
Get Started
Use Cases

Same agent, different user

One agent, invoked by two people in different directory groups, reaches different data, because policy reads group membership from the identity provider you already run.

You run one agent and many people use it. What each person’s request may reach should follow the groups you already maintain in your directory, without a second permission system to keep in step.

An agent usually gets one identity and one set of permissions. Whoever invokes it, the downstream system sees the same principal with the same access.

That flattens your directory. The careful work of putting people in groups, and the entitlements attached to those groups, stops at the agent’s front door. Someone in a read-only group and someone with write access invoke the same agent and get the same reach.

It also turns a convenience into an escalation path. If the agent’s static identity holds the union of what any of its users might need, then the least-privileged person invoking it has borrowed the most-privileged person’s access for the duration of a request. Nobody granted that, and nothing in the log distinguishes it from an ordinary call.

Maintaining a second permission table inside the agent does not fix it. Now group membership lives in two places, and the copy drifts the day someone changes teams.

flowchart LR
    A[Analyst] --> C[Your Agent]
    B[Administrator] --> C
    C -->|"One static identity, union of permissions"| D[Resource]
    D -->|"Same access for both"| E["Log: the agent did it"]
  • More than one person invokes the same agent, and they should not all reach the same data
  • Your identity provider already has the group structure that expresses who may see what
  • You want an entitlement change made in the directory to govern agent access too
  • You need to show a reviewer that the agent is not a way around existing group boundaries

Suppose a support agent can read customer records. Your tier-one group should reach contact details and open tickets. Your billing group should reach payment history. The same agent, asked the same question by two people, should answer differently, and it should be your directory that decides.

Where the difference you need is per record or per row rather than per Resource, the Resource enforces that itself. Keycard decides which Resource and which operation a request may reach.

Where nobody is present to authenticate, there is no user whose groups can be read. See Act on Behalf of Absent Users.

Where the distinction you want is about what the agent may do rather than who it acts for, the enforcement point is different. See Control Tool Calls.

Keycard evaluates policy on every credential request, and that evaluation can read the invoking user’s group membership from your identity Provider.

The agent stays one registered Application. What changes per request is the User it is acting for, and the groups that user carries. A policy that permits a Resource only when the subject’s groups contain a particular value produces one outcome for the analyst and another for the administrator, from the same agent and the same code.

Policy is default deny, and a forbid always beats a permit, so a request that matches nothing is refused rather than allowed through.

flowchart LR
    A[User signs in] -->|"ID token with groups"| B[Keycard session]
    B --> C[Your Agent requests a credential]
    C --> D{Policy evaluation}
    D -->|"subject_claims.groups matches"| E[Credential for that Resource]
    D -->|"no match"| F[Denied, logged with the deciding policy]
  1. The User signs in through your identity provider. Keycard federates over OpenID Connect, and Okta, Microsoft Entra, Auth0, and Google are all documented paths.
  2. Keycard reads the groups claim from that provider and carries it into policy evaluation as context.subject_claims.groups.
  3. Your agent requests a credential for one named Resource, acting for that User.
  4. Policy evaluates against the User, the Application, the Resource, and that group context. The full set of attributes policy can see is listed under entity properties.
  5. A permitted request yields a credential scoped to that User and Resource. A refused one is recorded as a Failure carrying access_denied and the name of the deciding policy, so you can read the rule that decided it.

The same agent gives different people different reach, and the difference is expressed once, in policy, against groups you already maintain.

Access follows your directory rather than a copy of it. When someone moves teams, you change one thing in your identity provider.

Every decision is attributable. The audit record names the person, the Application acting for them, and the Resource, so “why could they see that” is answerable from the log rather than by reading the agent’s code.

Group membership arrives at sign-in, so a change lands at the next sign-in. Keycard reads the groups claim from the ID token when the session is created, and that snapshot serves the session rather than being re-fetched per request. Removing someone from a group in your directory therefore governs their next session rather than one already running. Where you need access to stop sooner than that, revoking the grant, or disabling the person, is the mechanism that acts now rather than at their next sign-in.

You write the policies. Expressing the distinction once in policy is the point, and it means someone owns those rules and keeps them current as your group structure changes.

Group matching is exact. Cedar compares entity identifiers directly, without wildcards or negation, so a naming scheme that relies on prefixes needs the membership modelled rather than pattern-matched.

No, and it reads from yours on purpose. Your directory stays the system of record for who someone is and which groups they belong to. Keycard decides what their agent may reach, using that membership as an input. Where a team has no identity provider, that is the piece to solve first, because everything here derives from a verified person and their groups.

How does a reviewer confirm the boundary actually holds?

Section titled “How does a reviewer confirm the boundary actually holds?”

Run the identical task as two users in different groups and compare. Both requests appear in the Audit Log, the permitted one as a credential issuance naming the person and the Resource, the refused one as a Failure whose error message names the policy that decided it. That pair of records is the evidence, and it is reproducible on demand rather than asserted.

What happens if the group claim stops arriving?

Section titled “What happens if the group claim stops arriving?”

The policy stops matching, and under default deny that means access stops rather than opening up. It fails shut. The cost is that a provider misconfiguration looks like a policy denial, which is why the Aside above suggests confirming the claim in a decoded token before a first session.

Can we do this with roles instead of directory groups?

Section titled “Can we do this with roles instead of directory groups?”

Yes, and the two behave differently in one way worth knowing. Keycard roles are resolved when policy evaluates, so a role assignment change takes effect without waiting for a new session. Directory groups arrive as a sign-in snapshot. Where you need a change to bite immediately, a role is the mechanism that does that today.

  • A data agent where the finance group reaches revenue tables and everyone else reaches the product ones
  • An operations agent where on-call members may act on production and the rest may only read
  • A customer-facing assistant in a multi-tenant product, where the invoking user’s tenant group decides which tenant’s data is in reach
  • An internal search agent that indexes broadly and returns only what the asker’s groups already permit

The shape is the same each time. One agent, many invokers, and a distinction that already exists in your directory rather than one invented for the agent.