# Bot-Free Authentication in scan-plugins: How the Claude Plugins Community Action Handles Credentials

> Discover how scan-plugins achieves bot-free authentication using ephemeral WIF tokens or static API keys, ensuring secure credential handling for AI-powered policy scans.

- Repository: [Anthropic/claude-plugins-community](https://github.com/anthropics/claude-plugins-community)
- Tags: how-to-guide
- Published: 2026-08-24

---

**The scan-plugins composite action implements bot-free authentication by running a credential-free static analysis phase unconditionally while gating the AI-powered policy scan behind either ephemeral Workload Identity Federation (WIF) tokens or static API keys, skipping the policy scan entirely when no credentials are provided.**

The `scan-plugins` GitHub Action in the `anthropics/claude-plugins-community` repository validates external plugin submissions through a carefully architected two-phase process. This design ensures bot-free authentication is maintained by strictly separating deterministic static checks—which require no credentials—from optional AI-driven scans that demand proper Anthropic authentication.

## The Two-Phase Validation Architecture

The action is built to run two distinct phases with different security requirements:

- **Static "pin-check" (auth-free)** – Runs unconditionally and only requires `jq`. It clones each changed external entry at its pinned SHA and inspects any [`.mcp.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.mcp.json) launcher specifications. Because it never contacts Anthropic's API, it never requires credentials.

- **Claude policy scan (requires auth)** – Only executed when the runner has either a static API key or a Workload Identity Federation (WIF) token.

## The Auth-Free Static Pin Check

The static pin check operates completely without authentication. In [`.github/actions/scan-plugins/action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/scan-plugins/action.yml), the **Static pin check** step (lines 54-64) invokes [`scripts/static-pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/static-pin-check.sh) to perform deterministic validation.

This script clones each changed external entry at its pinned SHA and inspects any [`.mcp.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.mcp.json) launcher specifications. Because this phase never contacts Anthropic's API, it produces JSON output without exposing any secrets to the runner.

## Bot-Free Authentication Methods for Policy Scanning

When aiming to run the AI-powered policy scan, the action accepts two mutually exclusive authentication methods that determine how the Claude CLI authenticates with Anthropic's services.

### Static API Key Authentication

The action accepts an `anthropic-api-key` input parameter that passes a classic secret API key directly to the Claude CLI. While functional, this method exposes a long-lived secret to the workflow runner.

### Workload Identity Federation (WIF)

The preferred bot-free approach uses the `anthropic-federation-rule-id` input (a WIF rule ID formatted as `fdrl_…`). When this is set, the action mints a short-lived OIDC token and exchanges it for an Anthropic token, avoiding any static secret exposure.

According to the source code in [`action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/action.yml) (lines 66-78), the WIF flow creates a temporary file storing the OIDC JWT, continuously refreshes it, and injects the necessary environment variables for the Claude CLI:

- `ANTHROPIC_FEDERATION_RULE_ID`
- `ANTHROPIC_ORGANIZATION_ID`
- `ANTHROPIC_SERVICE_ACCOUNT_ID`
- `ANTHROPIC_IDENTITY_TOKEN_FILE`

## Skip Logic and Conditional Execution

If **neither** `anthropic-api-key` nor `anthropic-federation-rule-id` is supplied, the policy scan is deliberately skipped. The "Skip if no Anthropic auth configured" step (lines 35-40 in [`action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/action.yml)) checks for the presence of credentials and aborts the policy scan if absent.

When authentication *is* present, the workflow proceeds to install the Claude CLI (lines 26-63) and then run the main scan (lines 65-81), passing the appropriate auth variables to the underlying [`scan.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scan.sh) script.

In cases where the scan is skipped, the overall result is reported as `skipped`, but the auth-free pin check still produces its JSON output. This ensures that validation pipelines remain functional even without expensive AI credentials.

## Key Implementation Files

The bot-free authentication model is implemented across three core files:

- **[`.github/actions/scan-plugins/action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/scan-plugins/action.yml)** – Defines inputs, auth detection logic, and the conditional step sequence including the skip-if-no-auth logic.

- **[`.github/actions/scan-plugins/scripts/static-pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/scan-plugins/scripts/static-pin-check.sh)** – Implements the deterministic, auth-free pin inspection.

- **[`.github/actions/scan-plugins/scripts/scan.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/scan-plugins/scripts/scan.sh)** – Runs the Claude policy scan when authentication is available.

## Complete Workflow Examples

### Using Workload Identity Federation (Bot-Free)

This configuration uses ephemeral tokens rather than static secrets:

```yaml
jobs:
  validate:
    runs-on: ubuntu-latest
    permissions:
      id-token: write   # required for WIF

    steps:
      - uses: actions/checkout@v4
      - name: Scan plugins
        uses: ./.github/actions/scan-plugins
        with:
          anthropic-federation-rule-id: ${{ secrets.ANTHROPIC_FEDERATION_RULE_ID }}
          anthropic-organization-id: ${{ secrets.ANTHROPIC_ORG_ID }}
          anthropic-service-account-id: ${{ secrets.ANTHROPIC_SVAC_ID }}
          fail-on-findings: true

```

### Using Static API Key Authentication

For scenarios requiring classic authentication:

```yaml
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Scan plugins
        uses: ./.github/actions/scan-plugins
        with:
          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          fail-on-findings: true

```

Both configurations rely on the same underlying action; the decision to run the policy scan is made automatically based on which auth input is non-empty.

## Summary

- **The static pin check runs unconditionally** without any Anthropic credentials, providing deterministic validation of plugin manifests and pinned commits.
- **The Claude policy scan is strictly optional** and requires either `anthropic-api-key` or `anthropic-federation-rule-id`.
- **Workload Identity Federation enables true bot-free authentication** by minting short-lived OIDC tokens on-demand rather than exposing long-lived secrets.
- **Skip logic ensures graceful degradation** when credentials are absent, reporting `result=skipped` while preserving the static check output.

## Frequently Asked Questions

### What happens if I don't provide any authentication to scan-plugins?

If neither `anthropic-api-key` nor `anthropic-federation-rule-id` is provided, the action skips the AI-powered policy scan entirely (as implemented in lines 35-40 of [`action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/action.yml)). The workflow reports `result=skipped` for the scan phase but continues to execute the auth-free static pin check, ensuring baseline validation still occurs.

### How does Workload Identity Federation improve security over API keys?

Workload Identity Federation (WIF) eliminates long-lived secrets by minting short-lived OIDC tokens on-the-fly. According to the implementation in [`action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/action.yml) (lines 66-78), the action creates a temporary JWT file that continuously refreshes, injecting ephemeral credentials via environment variables rather than static API keys. This approach follows zero-trust principles and prevents credential leakage in CI logs.

### Which validation steps run without any Anthropic credentials?

Only the **static pin check** operates without credentials. Located at lines 54-64 in [`action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/action.yml) and implemented in [`static-pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/static-pin-check.sh), this phase clones repositories at their pinned SHA and validates [`.mcp.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.mcp.json) launcher specifications using only `jq`. It requires no network access to Anthropic's API and serves as the auth-free safety net.

### What files are inspected during the auth-free static pin check?

The [`static-pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/static-pin-check.sh) script inspects external plugin entries that have changed in the current commit, specifically examining the pinned SHA references and any [`.mcp.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.mcp.json) launcher configuration files. This deterministic analysis validates the plugin structure without executing remote code or accessing Anthropic services.