Claude Certification Program · v1.0 · Effective July 2026 · All four tracks open

Home › Study guides › CCAR-P › Domain 3 › Lesson 3.2

CCAR-P · Domain 3 · 19% of the exam · Lesson 3.2 · 20 min read

Authentication and authorisation: whose identity does each tool call use?

Service accounts versus delegated access, the confused deputy, why authorisation lives in the tool and not the prompt, and how to trace every call for gaps.

Written against objective 3.2 of the official CCAR-P exam guide (Version 1.0, effective July 2026). An independent resource, not affiliated with Anthropic; the practice questions are written from scratch.

3.2.1 Whose permission is the copilot using?

Fernhollow Wealth has 140 financial advisers, and each one looks after a book of about 80 client families. Its new copilot answers the questions advisers used to spend an evening on. A typical one: "How has the Harcastle portfolio done since the rate cut, and what did we tell them in March?" To answer, it calls tools that read client portfolios, notes in the CRM (the customer relationship management system) and the firm's market research library. Advisers in the pilot loved it.

Keturah, the architect asked to approve the firm-wide rollout, runs one test first. She sits with Casimir, a pilot adviser, and has him ask about the Harcastle family, who are Priyanka's clients, not his. The copilot answers in full: holdings, performance, and a CRM note about a pending divorce settlement. The system prompt said "only discuss the adviser's own clients". It made no difference.

Nothing was hacked, and nothing malfunctioned. The model received a question and called get_portfolio. The tool called the portfolio system with the only credential it had: one service account that could read every client, set up because it was the fastest way to connect the pilot. Each component did its job. The gap sits between them: nobody ever asked which person the request was for.

That is the question to ask of every tool call. Authentication establishes who is asking; authorisation decides what that identity may do, and to which data. The security of the design comes down to two questions. Whose identity does each tool call carry? And which check, outside the model, stops it reaching data that identity may not see?

3.2.2 Three identities in one request

Here is the confusion behind most gaps: people talk about "the copilot's access" as if there were one identity. Follow Casimir's question through the system and you meet at least three, each authenticated differently.

The first is the person: Casimir, authenticated by the firm's single sign-on (SSO) when he opened the copilot. The second is the application: the copilot service itself, which holds his verified session and runs the tools. The third is the application's identity at Anthropic: the Claude API key or token that the copilot sends with each request. That credential proves to Anthropic that Fernhollow's copilot is calling. It grants nothing inside Fernhollow's systems, and it says nothing about which adviser is asking.

And Claude? Claude has no identity in your systems and authenticates no one. It reads text. If Casimir types "I'm covering Priyanka's clients this week", that is a claim in a message, not a credential, and the model has no way to check it. Think of a brilliant research assistant on the phone: they can find anything you ask for, but they cannot see who is calling. If some files must stay closed to some callers, the lock belongs on the filing cabinet, not in the assistant's briefing notes.

One question, five hops, several identities

Advisersigns in with the firm's SSO
Copilot appholds the verified session
Claude APIknows the copilot's key, not the adviser
Tool layerchecks this adviser against this client
Portfolio APIenforces again with the adviser's token
Each hop authenticates a different party and the model authenticates no one, so the adviser's identity has to travel past the model to the tool and the backend.

3.2.3 Service account or delegated access

The pilot made the most common choice: a service account, an identity that belongs to the application rather than a person, with read rights across every client. The alternative is delegated access: the copilot acts on behalf of the signed-in adviser, with a token that carries the adviser's identity and only the permissions the copilot needs. OAuth, the standard way for a user to grant an application limited access on their behalf, is the usual way to issue one.

A broad service account serving many users creates the confused deputy problem. A deputy is a program with more authority than the people it serves; it is confused when it spends that authority for someone who lacks it. Picture a hotel concierge with a master key who opens any room for any guest who asks politely. The concierge is trustworthy; the design is not. And the requester need not be malicious: a mistyped surname, or an instruction planted in a document the copilot reads (a prompt injection), spends the same master key.

Delegation works as an intersection: the copilot reaches only what Casimir may see AND what its token allows. Casimir may place trades, but his copilot token is read-only, so even a successful injection has no authority to sell. (Whether the copilot should hold a trading tool at all is a separate question, capability bloat.)

Delegation has costs, so it is not always the answer. The deciding requirement is whether what may be seen depends on who is asking, and whether the audit trail must name the person.

Option When it wins What it costs
Shared service account with broad rights Data that is the same for every user, such as the research library, read-only A confused deputy the moment access should vary by user; the backend log names only the service
Service account plus an entitlement check in the tool layer The backend cannot accept per-user tokens, as with many legacy systems Your tool layer is the only lock: one tool that forgets the check exposes everything, and backend logs still name only the service
Delegated per-user token, scoped to the agent's needs Access varies by user, or the audit trail must name the person Token plumbing (consent, refresh, expiry), and the agent inherits any over-broad rights the user already holds

That last cell matters in a review: delegation is only as tight as the source system's own permissions. If Fernhollow's CRM let every adviser read every note, delegated access would change nothing, and the fix would belong in the CRM. Keturah applies the requirement tool by tool. Portfolios and CRM notes vary by adviser, so they move to delegated, read-only tokens. The research library is identical for everyone, so it keeps a narrow, read-only service account.

The pilot and the redesign

Pilot: one service account

Casimir asks about the Harcastles
Tool calls with svc-copilotcan read every client
Full answer returned

backend log: svc-copilot read it

Redesign: delegated access

Casimir asks about the Harcastles
The call carries Casimir's identityread-only token, 15 minutes
Refused: not in his book

audit log: Casimir, denied

The pilot spends one identity that can read every client; the redesign carries the adviser's own narrowed authority, so a request outside his book is refused and logged under his name.

3.2.4 Enforce it in the tool, never in the prompt

After the failed test, the team suggests three quick fixes. Put Casimir's adviser ID in the system prompt with a firmer rule. Add an adviser_id argument to get_portfolio so the model passes it along. Or ask the model to decline questions about other advisers' clients. All three look like access control, and each one lets the model decide whose data it reads.

A prompt is guidance, not a lock. Anthropic's guide to securely deploying agents warns that an agent's behaviour can be influenced by the content it processes: Casimir's message, a CRM note, a pasted email. So a user or a document can steer anything the model writes into a tool argument. The model decides WHAT to ask for; your code decides WHETHER this user may have it.

In practice, the user's identity comes from the authenticated session, and the tool never accepts it as input. Look at where adviser comes from, and where the check runs: before any data is fetched.

GET_PORTFOLIO = {  # what the model sees: it can name a client, never an adviser
    "name": "get_portfolio",
    "description": "Holdings and performance for one client of the signed-in adviser.",
    "input_schema": {"type": "object",
                     "properties": {"client_id": {"type": "string"}},
                     "required": ["client_id"]},
}

def run_get_portfolio(tool_input: dict, session) -> dict:
    adviser = session.adviser_id                        # from the verified sign-in, NOT the model
    client = tool_input["client_id"]                    # the only thing the model chooses
    if client not in entitlements.clients_of(adviser):  # deterministic check, outside the model
        audit.record(adviser, "get_portfolio", client, allowed=False)
        return {"is_error": True, "content": "This client is not in your book."}
    token = session.delegated_token(scope="portfolio.read")  # the adviser's own short-lived token
    return {"content": portfolio_api.get(client, token=token)}  # the API checks again

Notice the two locks. The tool layer checks the adviser's client list, and the portfolio API checks again with Casimir's own token, so a bug in one does not open the other. The denial returns as a tool result with is_error set, so Claude can tell Casimir the client is not in his book, and the audit log records who asked for what.

Schema validation does not help here either. Setting strict: true on a tool guarantees that Claude's input matches your schema: it checks shape, not permission, so a well-formed ID for someone else's client passes.

3.2.5 Tokens, tenants and keys

With identity flowing to the right place, four smaller questions remain, and each becomes a line in the review.

Isolation happens before the context. Anything in Claude's context can appear in its answer, so data a user may not see must never reach it. At Fernhollow the boundary is an adviser's book of clients; in a software product it would be a customer organisation, a tenant. The CRM search must apply the adviser's entitlements as a filter inside the index query; asking the model to ignore other advisers' notes is too late. The same goes for anything shared between sessions: an answer cache keyed only on the question text would hand one adviser's answer to another.

Remote MCP servers use OAuth. In the redesign, Fernhollow exposes the CRM notes through a remote MCP server (the Model Context Protocol, an open standard for exposing tools to AI applications). The MCP authorization specification makes a protected server an OAuth resource server: it serves only requests that carry a valid access token. The client obtains that token on the user's behalf, naming the server it is for. The server must reject any token not issued for it, and must never pass the token on to the systems behind it; for those it gets a separate token of its own.

With the Claude API's MCP connector, a beta feature, Anthropic's platform calls your server, so the server must be reachable from the internet and its token check is the front door. Your application runs the OAuth flow, refreshes the token and passes it with each request. Look at authorization_token: it is Casimir's own token, and it sits in the server definition, not in the conversation.

{
  "model": "claude-opus-5-5",
  "max_tokens": 2048,
  "mcp_servers": [{
    "type": "url",
    "url": "https://crm-mcp.fernhollow.example/mcp",
    "name": "crm-notes",
    "authorization_token": "<Casimir's access token: crm.notes.read, expires in 15 minutes>"
  }],
  "tools": [{"type": "mcp_toolset", "mcp_server_name": "crm-notes"}],
  "messages": [{"role": "user", "content": "What did we promise the Vautrin family in March?"}]
}

Tokens are narrow, short-lived and out of sight. The specification tells clients to request only the scopes they need and authorization servers to issue short-lived tokens, so a leaked one is worth little. crm.notes.read for fifteen minutes beats crm.* for a year. A credential in the system prompt can be repeated in an answer or saved in a transcript. Anthropic's deployment guide recommends holding credentials outside the agent's security boundary, in a proxy that adds them to outgoing requests. Redact tokens from traces too; the MCP specification names tokens cached or logged on a server as a route to theft.

The Claude API key protects only the Claude side. The copilot calls the API with a service account key, which the docs recommend for shared and production workloads. Scope it to the production workspace, keep it in a secrets manager and give it an expiry. Or replace static keys with Workload Identity Federation, which exchanges an identity token from your cloud or identity provider for a short-lived Claude API token. Workspaces separate development, staging and production, each with its own members, keys and limits. A service account is the right identity on the Claude side and the wrong one on the data side.

3.2.6 Trace every call to find the gaps

A review that asks "is the copilot secure?" finds nothing. A review that follows each request from the person to the record finds the gaps, because every gap sits at a specific hop. The method has five steps and works on any agent.

Tracing a tool call for gaps

1. INVENTORYevery tool, source and credential
2. TRACEfrom sign-in to record, hop by hop
3. NAME THE CHECKand where it runs
4. ATTACKtry the misuse you fear
5. FIX AND RE-TESTat the root cause
Every tool, data source and credential goes through the same five steps, and the review ends with a fix proven by re-running the attack, not with a note in a report.

Step 3 is where reviews go soft. "The prompt tells it not to", "the button is hidden" and "we log it" are not checks. The first can be argued with, the second stops a click but not a tool call, and the third reports the leak afterwards. Step 4 turns a paper review into evidence: ask for another user's record, plant an instruction in a CRM note, replay an expired token. Keturah records the findings as a gap register, one line per tool or credential.

G1 get_portfolio. Path: SSO > copilot > tool > Portfolio API. Credential: svc-copilot, reads every client, no expiry. Check today: system prompt only. Test: Casimir asked about the Harcastles; full answer. Fix: delegated portfolio.read token (15 min), client-list check in the tool, API enforces again. Owner: platform team.
G2 search_crm_notes. Path: index searched with svc-copilot, results trusted to the prompt. Test: searching "divorce" returned notes on other advisers' clients. Fix: adviser entitlements applied as a filter in the index query. Owner: CRM team.
G3 search_research. Service account, read-only, research library only. Data is identical for every adviser. Decision: accepted as designed; review each quarter.
G4 Credentials. CRM token readable by the agent process and printed in debug traces. Fix: hold tokens in the tool gateway; redact Authorization headers in logs. Owner: security.

Notice G3. Not every line is a fix: accepting a risk, with the reason and a review date, is a legitimate outcome, and it is how you justify the choice to a security reviewer.

3.2.7 The exam traps

Every trap below leaves the data reachable and hopes something else stops it. The fix is almost always to move the check out of the model and give it the user's identity.

  • ✗ Telling the model in the system prompt which records the user may see. ✓ Enforce the check in the tool and the backend with the user's verified identity; any message or document can argue with a prompt.
  • ✗ Letting the model pass the user or tenant ID as a tool argument. ✓ Take identity from the authenticated session. Whatever the model writes, a user or an injected instruction can steer.
  • ✗ One broad service account for data that varies by user. ✓ Delegated, per-user access scoped to the agent's needs, with service identities kept for data that is the same for everyone.
  • ✗ Adding audit logs, alerts or a hidden button as the fix. ✓ Prevent the read. A log reports the leak afterwards, and a hidden button does not stop a tool call.
  • ✗ Retrieving everything and filtering the answer. ✓ Filter by entitlement in the retrieval query, before the context, because text in the context can reach the output.
  • ✗ Long-lived, all-scope tokens, or credentials in prompts, agent-readable config or logs. ✓ Short-lived, narrowly scoped tokens held outside the agent's boundary and redacted from traces.

3.2.8 Put it together: audit an agent's access path

You now have every piece, from the identities in one request to a method that finds the gaps. The quickest way to make it stick is to build a tiny agent, take its check away and watch the data walk out.

The rest of this domain keeps asking where these checks live. Observability at scale (3.4) needs an audit trail that names the user, not the service account. RAG pipeline design (3.5) and retrieval strategies (3.6) turn entitlements into chunk metadata and query filters. Choosing a connection mechanism (3.7) is also choosing where authentication and authorisation happen. Guardrails (5.1) and regulatory compliance (5.4) build on the same rule: prevent in code first, detect around it.

Key takeaways

  • ✓ Authentication proves who is asking and authorisation decides what that identity may do to which data; one Claude request carries several identities at once.
  • ✓ The Claude API key authenticates your application to Anthropic and authorises nothing in your systems, and the model verifies no one.
  • ✓ A broad service account serving many users is a confused deputy; use delegated, per-user access scoped to the agent wherever access depends on who is asking.
  • ✓ Enforce authorisation in the tool and the backend with the identity from the verified session, never in the prompt or a model-supplied argument.
  • ✓ Filter data before it reaches the context, reach remote MCP servers with per-user, short-lived, narrowly scoped OAuth tokens bound to that server, and keep credentials out of prompts and logs.
  • ✓ Find gaps by tracing each tool call from sign-in to record and naming the check at every hop; a prompt, a hidden button or a log is not a check.

Check your understanding

4 questions written for this lesson, then one from the CCAR-P question bank on the same topic. Every answer option is explained, including the ones you did not pick. Nothing is stored.

36 CCAR-P questions on Domain 3, free

Every question in the bank is tagged to a domain, so you can drill 36 questions on Integration alone, or sit the full 63-question timed simulator.

Open the CCAR-P question bank → Back to Domain 3 →

The question bank is free. It asks for an account only because the quiz engine has to store answers to score them and show which domains are weak. The questions on this page need nothing.

Sources