Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
Denied team avatar

Denied Dev Hook

  • 5 repo stars
  • Updated August 4, 2026
  • denied-dev/denied-sdk

Enforce authorization before each tool call using Denied.dev

About

denied-dev-hook is a Claude Code skill in the AI & Agent Building category. Enforce authorization before each tool call using Denied.dev

  • denied-dev-hook
  • AI & Agent Building
  • AI-coding skill

Denied Dev Hook by the numbers

  • Data as of Aug 5, 2026 (Skillselion catalog sync)
/plugin marketplace add denied-dev/denied-sdk
/plugin install denied-dev-hook@denied-dev

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
repo stars5
Last updatedAugust 4, 2026
Repositorydenied-dev/denied-sdk

What it does

Enforce authorization before each tool call using Denied.dev

README.md

Denied SDK Plugin for Claude Code

Claude Code can execute powerful tools — shell commands, file operations, web searches, MCP servers, and more. Denied defines the boundaries of what your Claude Code can and cannot do: before any tool executes, this plugin checks with the Denied authorization server whether the agent is permitted to run it. If the policy says no, the tool call is blocked and the reason is returned to the agent. You define the boundaries; the plugin enforces them.

Prerequisites

  • Claude Code installed and working
  • Node.js 18+ (already required by Claude Code)
  • A Denied account and API key. Sign up at app.denied.dev

Quickstart

Step 1: Add the marketplace

claude plugin marketplace add denied-dev/denied-sdk

Step 2: Install the plugin

claude plugin install denied-dev-hook

Step 3: Set your API key

Set your API key as an environment variable:

export DENIED_API_KEY="your-api-key"

Alternatively, add the config directly in ~/.claude/settings.json or ./claude/settings.local.json:

{
  "enabledPlugins": {
    "denied-dev-hook@denied-dev": true
  },
  "env": {
    "DENIED_API_KEY": "your-api-key"
  }
}

Step 4: Restart Claude Code

Start a new Claude Code session. The plugin is now active — every tool call will be checked against your Denied policies.

Step 5: Verify it's working

When a tool call is blocked, Claude Code will display the denial reason inline. You can also check stderr output for lines like:

[denied-dev] Blocked tool call: Bash
[denied-dev] Blocked tool call: Write

Configuration reference

Settings resolve in this order: environment variableconfig file → built-in default. Environment variables always win when present.

Environment variable Config file key (~/.denied/config.json) Default Description
DENIED_API_KEY apiKey Required. API key for the Denied PDP.
DENIED_URL url https://api.denied.dev PDP endpoint. Only change for custom deployments.
DENIED_FAIL_MODE failMode open open = allow on error, closed = deny when PDP is unreachable.
DENIED_TIMEOUT_MS timeoutMs 15000 Timeout in milliseconds.
DENIED_CONFIG ~/.denied/config.json Path to the JSON config file. Set to read config from elsewhere.

Example ~/.denied/config.json:

{
  "apiKey": "your-api-key",
  "url": "https://api.denied.dev",
  "failMode": "open",
  "timeoutMs": 15000,
  "request": {
    "includeToolInput": true,
    "includeHookPayload": true,
    "includeLastUserPrompt": true,
    "maxContextBytes": 20000
  },
  "audit": {
    "enabled": false,
    "dir": "~/.denied/audit",
    "includeRawPayload": true,
    "includeMappedRequest": true,
    "includeDecision": true
  }
}

request.includeToolInput controls whether raw tool input is sent as bounded request context. request.includeLastUserPrompt (default true) controls whether the user's most recent prompt is read from the session transcript and added to the check context as last_user_prompt; it is extracted via a bounded tail read of transcript_path and is best-effort (a missing transcript, parse failure, or marker miss simply omits the field — it never delays or fails the authorization decision). The read has its own short independent deadline (~1s), so a stalled filesystem aborts the read rather than blocking the decision. request.maxContextBytes replaces oversized JSON values (e.g. tool_input, hook_payload) with a { "truncated": true, ... } preview; last_user_prompt is always kept as a string and, when over the cap, is truncated with an inline … [truncated N bytes] marker so the field type stays stable for policy matching. When audit.enabled is true, local JSONL debug records are written to ~/.denied/audit/denied-claude-code-hook.jsonl by default.

Security note: Audit logs may contain sensitive data. When audit.enabled is true, audit.includeRawPayload, audit.includeMappedRequest, request.includeToolInput, request.includeHookPayload, and request.includeLastUserPrompt default to true, so requests and audit records can include full tool inputs, hook payloads, the user's last prompt, file contents, shell commands, URLs, and credentials. Store audit logs only in a location with appropriate access controls.

Default behavior

Default-deny: With no policies configured in Denied, every tool call is blocked. This is intentional — you must explicitly define the boundaries for your agent by creating policies in the Denied dashboard.

Fail-open on error: If the Denied server is unreachable (network issue, server down) or DENIED_API_KEY is not set, tool calls are allowed through. This prevents the plugin from completely breaking the agent. Set DENIED_FAIL_MODE=closed for stricter enforcement. You'll see log entries like:

[denied-dev] Failed to reach Denied PDP: fetch failed

Authorization enforcement

The plugin enforces Denied authorization checks on every tool call, regardless of Claude Code's permission mode.

Permission mode Claude Code permissions Denied authorization
default, plan, acceptEdits Normal prompts Enforced
dontAsk Auto-approved Enforced
bypassPermissions (--dangerously-skip-permissions) Skipped Enforced

--dangerously-skip-permissions bypasses Claude Code's built-in permission prompts, but it does not bypass Denied policy checks. This is intentional — Denied enforces organizational boundaries that are orthogonal to local permission delegation.

How it works

For each tool call, the plugin sends an authorization check to the Denied server:

  • Subject: claude-code://<sessionId> with cwd and permission_mode as properties
  • Action: execute
  • Resource: tool://<toolName> with tool_use_id and, by default, bounded tool_input as properties
  • Context: the integration name, the hook event, and — by default — the bounded hook payload and the user's most recent prompt (last_user_prompt)

The Denied server evaluates the request against your policies and returns allow or deny. If denied, the block reason is fed back to the agent so it can adapt its behavior.

Creating policies

After installing the plugin, all tool calls are blocked by default. You need to create policies to define what your agent is allowed to do.

Every blocked tool call is logged as an authorization decision in the Denied dashboard. These decision logs capture the full context of each request — the session identity, the tool name, and the parameters (command, file path, etc.).

The Denied dashboard includes an AI policy generator that can read these decision logs and produce least-privilege policies for you. This means you can start with default-deny, let the agent run into the boundaries, then review the decision logs and use the AI policy generator to create precise allow rules.

Troubleshooting

Symptom Meaning Fix
Blocked tool call: <name> Policy denied the tool call Working as intended. Create an allow policy in the Denied dashboard if the tool should be permitted.
Failed to reach Denied PDP: ... Plugin can't reach the Denied server Check DENIED_URL is correct and network connectivity.
HTTP 401 or 403 Invalid or missing API key Check DENIED_API_KEY env var.
DENIED_API_KEY is not set No API key configured Set the DENIED_API_KEY environment variable.
No [denied-dev] lines, tools run freely Plugin not loaded Verify the plugin is installed (claude plugin list) and restart Claude Code.

Uninstalling

claude plugin uninstall denied-dev-hook

Restart Claude Code after uninstalling. This removes the plugin and its hooks — no manual cleanup needed.

Links

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.