Claude Code GitHub Actions: Authentication & Permissions Analysis
Date: 2025-12-04
Status: Root Cause Identified
Severity: Configuration Issue (Not a Bug)
Executive Summary
The perceived “approval requirement” for GitHub CLI commands in Claude Code workflows is NOT a bug but a deliberate security feature. Claude Code, when invoked via anthropics/claude-code-action@v1, operates with GitHub authentication automatically provided by the action itself - not through environment variables like GH_TOKEN. The workflows are correctly configured, but understanding the authentication mechanism is critical for proper usage.
Root Cause Analysis
Issue Description
Users may expect Claude Code to automatically have access to GitHub CLI (gh) commands within workflows, similar to how workflow shell steps can use GH_TOKEN: $. However, Claude Code’s authentication mechanism is fundamentally different.
Core Problem: Authentication Context Separation
There are two distinct authentication contexts in these workflows:
1. Workflow Shell Steps Authentication
- name: Update issue labels based on outcome
run: |
gh issue view $
env:
GH_TOKEN: $ # ← Shell environment variable
Characteristics:
- Uses
GITHUB_TOKENsecret as an environment variable - GitHub CLI (
gh) automatically detectsGH_TOKENenvironment variable - Works immediately in shell scripts
- Scoped by workflow
permissions:block
2. Claude Code Execution Authentication
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: $
claude_args: '--allowed-tools "Bash(gh pr comment:*)"'
Characteristics:
- Uses GitHub App authentication (installed via
/install-github-appin Claude CLI) - Authentication is managed internally by the action
- Does NOT use
GH_TOKENenvironment variable - Requires explicit tool permission grants via
--allowed-tools
How Claude Code Action Handles Authentication
Based on the action documentation and source code analysis:
- GitHub App Installation:
- When you run
/install-github-appin Claude CLI, it installs the official “Claude Code” GitHub App - The app requests permissions:
contents,pull-requests,issues,discussions,actions,checks,workflows - The app generates a short-lived, repository-scoped token
- When you run
- Token Injection:
- The
anthropics/claude-code-action@v1action automatically obtains a GitHub App token - This token is injected into Claude Code’s execution environment
- Claude Code uses this token for all GitHub API/CLI operations
- The
- Permission Verification:
- The action verifies that the triggering user has write access to the repository (security feature)
- Bots are blocked by default (can be enabled with
allowed_botsinput) - The GitHub App token respects the workflow’s
permissions:block
- Tool Access Control:
- By default, Claude Code has NO access to arbitrary Bash commands
- Must explicitly grant access via
claude_args: '--allowed-tools "Bash(...)" - GitHub CLI commands (
gh) must be explicitly allowed
Why You Don’t See Approval Prompts
The authentication “just works” because:
- You ran
/install-github-appin Claude CLI (one-time setup) - The GitHub App is installed on the
cloudnnj/momentumrepository - The
CLAUDE_CODE_OAUTH_TOKENsecret is configured in repository settings - The action automatically uses the GitHub App token for Claude Code execution
- No additional
github_tokeninput is needed (only for custom GitHub Apps)
Workflow-by-Workflow Analysis
1. claude-auto-fix.yml
Status: ✅ Correctly Configured
Authentication Setup:
permissions:
contents: write # Push branches
pull-requests: write # Create PRs
issues: write # Comment & label issues
id-token: write
actions: read
steps:
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: $
claude_args: '--allowed-tools "Bash(*),Read,Write,Edit,Glob,Grep,Task"'
Analysis:
- ✅ Uses
CLAUDE_CODE_OAUTH_TOKENfor Claude authentication - ✅ Grants
Bash(*)- allows ALL Bash commands includinggh - ✅ Workflow shell steps correctly use
GH_TOKEN: $ - ✅ Permissions are appropriate for creating PRs and commenting
Why GitHub CLI Works for Claude:
Bash(*)wildcard allows all Bash commands- GitHub App authentication is automatically injected by the action
- Claude can run
gh pr create,gh issue comment, etc. without approval
Potential Issue:
Bash(*)is VERY permissive - allows unrestricted command execution- Consider restricting to:
Bash(gh *),Bash(git *),Bash(npm test)
2. claude-clarification-response.yml
Status: ✅ Correctly Configured (Same as claude-auto-fix.yml)
Authentication Setup:
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read
steps:
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: $
claude_args: '--allowed-tools "Bash(*),Read,Write,Edit,Glob,Grep,Task"'
Analysis: Same as claude-auto-fix.yml - correctly configured with broad Bash permissions.
3. claude-code-review.yml
Status: ⚠️ Restrictive Configuration (May Need Adjustment)
Authentication Setup:
permissions:
contents: read # ← Read-only!
pull-requests: read # ← Read-only!
issues: read # ← Read-only!
id-token: write
steps:
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: $
claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
Analysis:
- ✅ Uses
CLAUDE_CODE_OAUTH_TOKENfor Claude authentication - ✅ Explicitly allows specific
ghcommands (secure pattern!) - ⚠️ PROBLEM: Permissions are read-only but allows
gh pr comment! - ❌
gh pr commentwill FAIL because workflow haspull-requests: read(not write)
Issue:
claude_args: '--allowed-tools "Bash(gh pr comment:*)"' # ← Requires pull-requests: write!
Why This Fails:
- Claude attempts to run
gh pr comment ... - GitHub App token respects workflow
permissions:block - Token only has
pull-requests: readpermission - GitHub API rejects the comment creation (403 Forbidden)
Fix Required:
permissions:
contents: read
pull-requests: write # ← Change from read to write
issues: read
id-token: write
OR remove gh pr comment from allowed tools:
claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
4. claude.yml
Status: ✅ Minimal Configuration (Read-Only)
Authentication Setup:
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
actions: read
steps:
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: $
# NO claude_args specified - uses defaults
Analysis:
- ✅ Uses
CLAUDE_CODE_OAUTH_TOKENfor Claude authentication - ✅ No
claude_argsmeans NO Bash access (secure!) - ✅ Claude can only use built-in file operations and read GitHub context
- ✅ Cannot run
ghcommands (not in default allowed tools)
Default Allowed Tools (when claude_args not specified):
- File operations: Read, Write, Edit, Glob, Grep
- Git operations: Read-only git commands
- Comment management: Creating/updating comments (if permissions allow)
Why This Works:
- This workflow is for interactive
@claudementions - Users ask questions, Claude responds with analysis
- No need for Bash/gh commands - just file reading and analysis
Key Insights
1. GitHub Token vs OAuth Token
| Aspect | GITHUB_TOKEN (Shell) |
CLAUDE_CODE_OAUTH_TOKEN (Claude) |
|---|---|---|
| Purpose | Authenticate shell commands | Authenticate Claude Code execution |
| Scope | Workflow steps only | Claude Code internal operations |
| Usage | env: GH_TOKEN: $ |
with: claude_code_oauth_token: $ |
| Permissions | Defined by workflow permissions: |
Defined by GitHub App + workflow permissions: |
| Setup | Automatic (GitHub provides) | Manual (via /install-github-app) |
2. The --allowed-tools Flag is Critical
Default Behavior:
# Without claude_args, Claude CANNOT run Bash commands
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: $
Granting Bash Access:
# Allow specific gh commands (SECURE)
claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh pr list:*)"'
# Allow all Bash commands (DANGEROUS)
claude_args: '--allowed-tools "Bash(*)"'
3. Permissions Hierarchy
Authentication flows through this hierarchy:
- GitHub App Installation (organization/repository level)
- Installed via
/install-github-appin Claude CLI - Defines maximum possible permissions
- Installed via
- Workflow Permissions Block (workflow level)
permissions: contents: write pull-requests: write- Restricts what the GitHub App token can do in this workflow
- Allowed Tools Configuration (action level)
claude_args: '--allowed-tools "Bash(gh pr comment:*)"'- Controls what commands Claude can execute
Result: Most restrictive permission wins.
Answers to Original Questions
1. What is the root cause of any permission/approval issues?
Answer: There is no “approval issue” in the traditional sense. The workflows are configured correctly. Any perceived approval prompts would be due to:
- Missing GitHub App Installation: If
/install-github-appwasn’t run, the GitHub App isn’t installed - Missing OAuth Token Secret: If
CLAUDE_CODE_OAUTH_TOKENsecret isn’t configured - Permission Mismatch: When
claude_argsallows a command but workflowpermissions:doesn’t grant the required permission (e.g.,claude-code-review.yml)
2. How does anthropics/claude-code-action handle GitHub authentication for Claude?
Answer: The action uses GitHub App authentication:
- User runs
/install-github-appin Claude CLI (one-time setup) - This installs the “Claude Code” GitHub App on the repository
- The action obtains a short-lived, repository-scoped token from the GitHub App
- This token is automatically injected into Claude Code’s execution environment
- Claude Code uses this token for all GitHub API/CLI operations
- The token respects the workflow’s
permissions:block
No manual token passing required - it’s automatic!
3. Are the --allowed-tools arguments sufficient for GitHub CLI access?
Answer: Yes, BUT you must ensure:
- ✅
claude_argsincludesBash(gh ...)patterns - ✅ Workflow
permissions:grants required permissions - ✅
CLAUDE_CODE_OAUTH_TOKENsecret is configured - ✅ GitHub App is installed on the repository
Example Patterns:
# Allow all gh commands (broad)
--allowed-tools "Bash(gh *)"
# Allow specific gh subcommands (secure)
--allowed-tools "Bash(gh issue view:*),Bash(gh pr comment:*)"
# Allow all Bash commands (dangerous)
--allowed-tools "Bash(*)"
4. What alternative approaches exist for enabling Claude to interact with GitHub?
Alternatives:
- Current Approach (Recommended): GitHub App +
CLAUDE_CODE_OAUTH_TOKEN- ✅ Most secure (scoped tokens)
- ✅ Automatic token management
- ✅ No token expiration issues
- Custom GitHub App: Use
github_tokeninput ```yaml- uses: anthropics/claude-code-action@v1 with: github_token: $ claude_args: ‘–allowed-tools “Bash(gh *)”’ ```
- ⚠️ Only for advanced use cases
- ⚠️ Requires managing your own GitHub App
- Personal Access Token (NOT RECOMMENDED):
```yaml
- uses: anthropics/claude-code-action@v1 with: anthropic_api_key: $ claude_args: ‘–allowed-tools “Bash(*)”’ env: GH_TOKEN: $ ```
- ❌ Less secure (long-lived tokens)
- ❌ Broader permissions than needed
- ❌ Harder to audit
5. Is there a difference between workflow shell steps using GH_TOKEN vs Claude Code using gh commands?
Answer: Yes, fundamentally different mechanisms:
| Aspect | Workflow Shell Steps | Claude Code Bash Tool |
|---|---|---|
| Authentication | env: GH_TOKEN: $ |
GitHub App token (automatic) |
| Token Type | Workflow-generated token | GitHub App installation token |
| Scope | Shell environment only | Claude Code execution context |
| Command Execution | Direct shell execution | Executed through Claude Code’s tool system |
| Permission Check | Workflow permissions: block |
Workflow permissions: + --allowed-tools |
| Token Lifetime | Duration of workflow run | Duration of Claude Code execution |
Example:
jobs:
test:
permissions:
issues: write
steps:
# Shell step - uses GITHUB_TOKEN
- name: Comment via shell
run: gh issue comment 123 --body "Hello"
env:
GH_TOKEN: $ # ← Shell env var
# Claude Code - uses GitHub App token (automatic)
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: $
prompt: "Comment on issue #123 with 'Hello'"
claude_args: '--allowed-tools "Bash(gh issue comment:*)"'
# ↑ GitHub App token automatically available, NO env var needed
Recommendations
1. Fix claude-code-review.yml Permission Mismatch
Current Problem:
permissions:
pull-requests: read # ← Read-only but allows gh pr comment!
Solution Option A (Grant write permission):
permissions:
contents: read
pull-requests: write # ← Change to write
issues: read
id-token: write
Solution Option B (Remove comment tool):
claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
# Removed: Bash(gh pr comment:*)
Recommended: Option A - code review should be able to comment
2. Tighten Bash Permissions in Auto-Fix Workflows
Current:
claude_args: '--allowed-tools "Bash(*),Read,Write,Edit,Glob,Grep,Task"'
# ↑ VERY PERMISSIVE - allows ANY Bash command
Recommended:
claude_args: '--allowed-tools "Bash(gh *),Bash(git *),Bash(npm test),Bash(npm run *),Read,Write,Edit,Glob,Grep,Task"'
# ↑ Restricted to specific command patterns
Why This Matters:
Bash(*)allows execution of ANY shell command- If Claude is compromised or makes an error, it could run dangerous commands
- Principle of least privilege: only grant what’s needed
3. Add Additional Permissions for CI/CD Integration (Optional)
If you want Claude to analyze CI/CD failures:
permissions:
contents: write
pull-requests: write
issues: write
actions: read # ← Add this
id-token: write
steps:
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: $
additional_permissions: |
actions: read # ← Add this
This enables Claude to use:
gh run list- View workflow runsgh run view- View workflow run detailsgh run watch- Monitor workflow progress
4. Document Tool Permissions
Create a comment in each workflow explaining why specific tools are allowed:
# Tool Permissions Explanation:
# - Bash(gh *): Required for creating PRs, commenting, and labeling issues
# - Bash(git *): Required for branch management and commits
# - Bash(npm test): Required for running tests to verify fixes
# - Read,Write,Edit: Required for file operations
# - Glob,Grep: Required for code analysis
# - Task: Required for multi-step workflows
claude_args: '--allowed-tools "Bash(gh *),Bash(git *),Bash(npm test),Read,Write,Edit,Glob,Grep,Task"'
Security Best Practices
1. Never Commit Secrets
❌ WRONG:
claude_code_oauth_token: "oauth_abc123..." # EXPOSED!
✅ CORRECT:
claude_code_oauth_token: $
2. Use Principle of Least Privilege
❌ TOO PERMISSIVE:
permissions:
contents: write
pull-requests: write
issues: write
actions: write
checks: write
workflows: write # Overkill!
✅ MINIMAL PERMISSIONS:
permissions:
contents: write # Only what's needed
pull-requests: write
issues: write
3. Restrict Allowed Tools
❌ TOO BROAD:
claude_args: '--allowed-tools "Bash(*)"' # ANY command!
✅ SPECIFIC PATTERNS:
claude_args: '--allowed-tools "Bash(gh issue *),Bash(gh pr *),Bash(npm test)"'
4. Verify User Access
Current workflows correctly check that triggering user has write access:
jobs:
auto-fix:
# Only runs if user has write access (automatic check by action)
runs-on: ubuntu-latest
permissions:
contents: write
No additional configuration needed - the action automatically verifies user permissions.
5. Review Workflow Logs
Monitor workflow logs for unexpected behavior:
# View recent workflow runs
gh run list --workflow=claude-auto-fix.yml --limit 10
# View specific run details
gh run view 12345
# Download logs
gh run download 12345
Testing & Verification
Test Checklist
- Verify GitHub App is installed on repository
- Verify
CLAUDE_CODE_OAUTH_TOKENsecret is configured - Test each workflow with a sample issue/PR
- Verify Claude can create PRs (auto-fix workflows)
- Verify Claude can comment on issues (clarification workflow)
- Check that unauthorized users cannot trigger workflows
- Monitor workflow logs for authentication errors
Verification Commands
# Check GitHub App installation
gh api /repos/cloudnnj/momentum/installation
# Check repository secrets (names only, not values)
gh secret list
# Test gh commands with workflow permissions
gh auth status
# List workflow runs
gh run list --workflow=claude-auto-fix.yml
# View workflow configuration
gh workflow view claude-auto-fix.yml
Troubleshooting
Issue: “GraphQL: Resource not accessible by integration”
Cause: Workflow permissions don’t grant required access
Solution: Check permissions: block matches required operations
# If Claude needs to comment:
permissions:
issues: write # Required for issue comments
pull-requests: write # Required for PR comments
Issue: “The operation requires elevated permissions”
Cause: Triggering user doesn’t have write access to repository
Solution:
- Verify user has write/admin role in repository settings
- Or use
allowed_non_write_users(RISKY - see security docs)
Issue: “Command not found: gh”
Cause: gh command not allowed in claude_args
Solution: Add to allowed tools:
claude_args: '--allowed-tools "Bash(gh *)"'
Issue: “Authentication failed”
Cause: CLAUDE_CODE_OAUTH_TOKEN not configured or expired
Solution:
- Run
/install-github-appin Claude CLI - Follow prompts to generate new token
- Update secret in GitHub repository settings
Conclusion
The Claude Code GitHub Actions workflows are correctly configured and do not require approval for GitHub CLI commands. Authentication is handled automatically through the GitHub App integration. The key points:
- ✅ Authentication is automatic - no manual token management needed
- ✅ Workflows use correct authentication method -
CLAUDE_CODE_OAUTH_TOKEN - ⚠️ One permission mismatch found -
claude-code-review.ymlneedspull-requests: write - ⚠️ Overly permissive Bash access - Consider restricting
Bash(*)to specific patterns - ✅ Security model is sound - GitHub App + least privilege permissions
Next Steps
- Fix claude-code-review.yml permission mismatch
- Tighten Bash permissions in auto-fix workflows
- Document tool permissions in workflow comments
- Monitor workflow logs for any authentication issues
- Consider adding CI/CD integration permissions if needed
The workflows are production-ready with minor recommended improvements.
References: