Security and Troubleshooting¶
Token Exposure Risk
Tokens are automatically masked in GitHub Actions logs, but manual echo/print statements can bypass masking. Never output tokens for debugging purposes.
Security Best Practices¶
1. Token Masking¶
Tokens are automatically masked in logs, but be careful with debugging.
# ✅ GOOD: Token automatically masked
- name: Generate token
id: app_token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.CORE_APP_ID }}
private-key: ${{ secrets.CORE_APP_PRIVATE_KEY }}
# ❌ BAD: Don't output tokens for debugging
- run: echo "Token: ${{ steps.app_token.outputs.token }}"
2. Scope Minimization¶
Use the narrowest scope possible.
# ✅ GOOD: Explicit repository list
- uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.CORE_APP_ID }}
private-key: ${{ secrets.CORE_APP_PRIVATE_KEY }}
repositories: |
repo1
repo2
# ⚠️ USE WITH CAUTION: Org-wide access
- uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.CORE_APP_ID }}
private-key: ${{ secrets.CORE_APP_PRIVATE_KEY }}
owner: your-org # Access to all installed repos
3. Secure Credential Storage¶
# ✅ GOOD: Use organization or repository secrets
with:
app-id: ${{ secrets.CORE_APP_ID }}
private-key: ${{ secrets.CORE_APP_PRIVATE_KEY }}
# ❌ BAD: Never hardcode credentials
with:
app-id: "123456"
private-key: "-----BEGIN RSA PRIVATE KEY-----..."
4. Audit Logging¶
Log token generation for audit trails.
- name: Generate token (audited)
id: app_token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.CORE_APP_ID }}
private-key: ${{ secrets.CORE_APP_PRIVATE_KEY }}
owner: adaptive-enforcement-lab
- name: Log token generation
run: |
echo "::notice::Generated installation token for adaptive-enforcement-lab"
echo "Workflow: ${{ github.workflow }}"
echo "Actor: ${{ github.actor }}"
echo "Repository: ${{ github.repository }}"
5. Permission Boundaries¶
Configure minimal app permissions.
# In your GitHub App settings, grant only necessary permissions:
# - Repository permissions:
# - Contents: Read (for reading code)
# - Issues: Write (for creating issues)
# - Pull Requests: Write (for creating PRs)
# - Organization permissions:
# - Members: Read (for listing org members)
Troubleshooting¶
Token Generation Fails¶
Causes:
- App not installed on target repository/organization
- Invalid app ID or private key
- App permissions insufficient
Solution:
- name: Verify app installation
env:
GH_APP_ID: ${{ secrets.CORE_APP_ID }}
GH_APP_PRIVATE_KEY: ${{ secrets.CORE_APP_PRIVATE_KEY }}
run: |
# List installations (requires JWT)
gh api /app/installations --jq '.[] | {id: .id, account: .account.login}'
# Verify installation exists for target organization
Repository Not Accessible¶
Causes:
- Repository not in
repositoriesparameter - App not installed on repository
- Insufficient app permissions
Solution:
# Check repository list
- name: Debug repository access
run: |
echo "Attempting to access: ${{ github.repository }}"
echo "Token scoped to: ${{ matrix.repository }}"
# Ensure repository is in scope
- uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.CORE_APP_ID }}
private-key: ${{ secrets.CORE_APP_PRIVATE_KEY }}
repositories: |
${{ github.event.repository.name }} # Add current repo
other-repo
Token Expired Mid-Workflow¶
Cause: Token expired after 1 hour.
Solution:
# Regenerate token for long-running workflows
- name: Long processing step
run: |
# ... work that takes >30 minutes ...
- name: Refresh token
id: refreshed_token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.CORE_APP_ID }}
private-key: ${{ secrets.CORE_APP_PRIVATE_KEY }}
owner: adaptive-enforcement-lab
- name: Continue with fresh token
env:
GH_TOKEN: ${{ steps.refreshed_token.outputs.token }}
run: |
# ... more work ...
Private Key Format Issues¶
Cause: Invalid PEM format in secret.
Solution:
# Verify private key format in GitHub Secrets
# Key must include newlines and markers:
-----BEGIN RSA PRIVATE KEY-----
[key content with newlines]
-----END RSA PRIVATE KEY-----
# Test private key locally
openssl rsa -in private-key.pem -check
Performance Considerations¶
Token Generation Overhead¶
Each token generation adds ~500ms-1s to workflow execution.
# ❌ Inefficient: Multiple token generations
- id: token1
uses: actions/create-github-app-token@v2
...
- run: gh api /repos/org/repo1
env:
GH_TOKEN: ${{ steps.token1.outputs.token }}
- id: token2
uses: actions/create-github-app-token@v2
...
- run: gh api /repos/org/repo2
env:
GH_TOKEN: ${{ steps.token2.outputs.token }}
# ✅ Efficient: Reuse token across steps
- id: app_token
uses: actions/create-github-app-token@v2
with:
owner: org
- run: |
gh api /repos/org/repo1
gh api /repos/org/repo2
env:
GH_TOKEN: ${{ steps.app_token.outputs.token }}
Rate Limits¶
Installation tokens share the installation's rate limit: 5,000 requests/hour per installation.
- name: Check rate limit
env:
GH_TOKEN: ${{ steps.app_token.outputs.token }}
run: |
gh api /rate_limit --jq '.resources.core | {
limit: .limit,
remaining: .remaining,
reset_at: (.reset | strftime("%Y-%m-%d %H:%M:%S"))
}'
Caching for Repeated Operations¶
- name: Generate token (cache-friendly)
id: app_token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.CORE_APP_ID }}
private-key: ${{ secrets.CORE_APP_PRIVATE_KEY }}
owner: adaptive-enforcement-lab
- name: Cache token for reuse
run: |
# Store token in environment for all subsequent steps
echo "GH_TOKEN=${{ steps.app_token.outputs.token }}" >> $GITHUB_ENV
- name: Operation 1
run: gh repo list adaptive-enforcement-lab
- name: Operation 2
run: gh issue list --repo adaptive-enforcement-lab/repo1
- name: Operation 3
run: gh pr list --repo adaptive-enforcement-lab/repo2
# All operations reuse the same token from environment
Related Documentation¶
- Authentication Decision Guide - Choose the right auth method
- Token Refresh Patterns - Token lifecycle and expiration handling
- JWT Authentication - App-level authentication for installation discovery
- OAuth User Authentication - User-context operations
- Storing Credentials - Secret management patterns
References¶
- actions/create-github-app-token - Official action documentation
- GitHub Apps Authentication
- Installation Access Tokens