Claude Agent SDK keeps its own auth hook. Authdog stays the identity provider. The sample attaches an agent access token there and refuses the run when that token is missing or userinfo rejects it.

Sample: [claude-agent/python](https://github.com/authdog/agents-samples/tree/main/claude-agent/python). Python 3.10+. Package `claude-agent-sdk==0.2.172`.

Channel auth, machine credentials, tool checks, and instructions for this framework are the other pages under Claude Agent SDK in [AI](/docs/ai/claude-agent/channel-auth).

## The hook

```python
async def require_authdog(input_data, tool_use_id, context):
    token = token_for_this_run()
    if subject_if_accepted(token) is None:
        return {
            "hookSpecificOutput": {
                "hookEventName": input_data["hook_event_name"],
                "permissionDecision": "deny",
                "permissionDecisionReason": "unauthorized",
            }
        }
    return {}

options = ClaudeAgentOptions(
    hooks={"PreToolUse": [HookMatcher(hooks=[require_authdog])]}
)
```

There is no matcher, so the hook runs for every tool. `permissionDecision: deny` stops that call. An empty object lets the normal permission flow continue. The token comes from the host (`token_for_this_run`), not from `input_data["tool_input"]`. The model does not get to supply it. Tests call the hook. They do not need `ANTHROPIC_API_KEY`.

This is agent identity: `client_credentials`, then this hook. It is not [Agent Sign-In](/docs/agent-sign-in). A browser sign-in does not replace the hook.

## What you should see

The hook returns `permissionDecision` `deny` when the token is missing or userinfo rejects it. The tool does not run.

The hook returns `{}` when userinfo accepts the bearer. A `whoami` tool may then return that subject.

`pytest` in `claude-agent/python` checks both. It does not call a model.

## Configure

| Name | Purpose |
| --- | --- |
| Host-held access token | What the hook sends to userinfo. Not a tool argument. |

The shared exchange is in [Agent frameworks](/docs/agent-frameworks#mint-the-bearer). There is no refresh token. Repeat it before `expires_in`.

> **Caution**
>
> Do not commit the client secret, and do not put the access token in the prompt. The public key selects the identity host. It does not mint tokens.

## Related

| Read | To learn how to |
| --- | --- |
| [Agent frameworks](/docs/agent-frameworks) | Mint the bearer this hook checks |
| [Pydantic AI](/docs/agent-frameworks/pydantic-ai) | The previous hook |
| [Mastra](/docs/agent-frameworks/mastra) | The next hook |
| [Custom channel auth for Claude Agent SDK](/docs/ai/claude-agent/channel-auth) | The same check, as the auth boundary |
