Complete step-by-step instructions for configuring the GitHub Actions integration in Salesforce.
Before you begin, ensure you have:
- ✅ GitHub organization or repository with admin access
- ✅ Salesforce org (sandbox or production)
- ✅ Salesforce CLI installed (
sfcommand) - ✅ OpenSSL installed (for key conversion)
- ✅ Git installed
For an organization:
GitHub → Your Organization → Settings → Developer settings → GitHub Apps → New GitHub App
For a personal account:
GitHub → Settings → Developer settings → GitHub Apps → New GitHub App
Fill in the following fields:
| Field | Value |
|---|---|
| GitHub App name | Salesforce Integration - [Your Org Name] |
| Homepage URL | Your Salesforce org URL (e.g., https://mycompany.my.salesforce.com) |
| Webhook URL | https://[your-org].my.salesforce.com/services/apexrest/githubwebhook |
| Webhook secret | Generate a strong random string (save this!) |
Example webhook secret generation:
openssl rand -hex 32Under Repository permissions, set:
| Permission | Access | Purpose |
|---|---|---|
| Actions | Read and write | Trigger workflows, read workflow status |
| Contents | Read and write | Required for repository_dispatch events |
| Metadata | Read-only | Automatically set (repository metadata) |
Contents: write is required for repository_dispatch events. If you only want to use workflow_dispatch, Contents: read is sufficient.
Under Subscribe to events, select:
- ✅ Workflow job
- ✅ Workflow run
Choose one:
- ☑️ Only on this account (recommended for testing)
- ☐ Any account
Click Create GitHub App button.
After creation, you'll see your App ID on the app settings page. Save this number!
Example: 123456
On your GitHub App settings page:
- Scroll to Private keys section
- Click Generate a private key
- A
.pemfile will download automatically - Save this file securely!
The private key needs to be converted to base64 format without headers/footers for storage in Salesforce.
macOS/Linux:
cat your-github-app.pem | grep -v "BEGIN\|END" | tr -d '\n' > private_key_base64.txtWindows (PowerShell):
Get-Content your-github-app.pem | Where-Object { $_ -notmatch "BEGIN|END" } | Out-String | ForEach-Object { $_.Replace("`r`n","").Replace("`n","") } | Set-Content private_key_base64.txtThe resulting private_key_base64.txt should be a single line of base64 text without any line breaks.
# Check it's a single line
wc -l private_key_base64.txt
# Output should be: 1 private_key_base64.txt
# Check length (should be ~1600-3200 characters)
wc -c private_key_base64.txt- Go to your GitHub App settings page
- Click Install App in the left sidebar
- Select your organization
- Choose repositories:
- ☑️ Only select repositories → Select your target repo
- ☐ All repositories
- Click Install
After installation, look at the URL in your browser:
https://github.com/organizations/YOUR_ORG/settings/installations/12345678
^^^^^^^^
This is your Installation ID
Save this Installation ID!
git clone https://github.com/yourorg/sf-develop-demo.git
cd sf-develop-demoFor scratch org:
sf org login web -a MyScratchOrg -dFor sandbox:
sf org login web -a MySandbox -r https://test.salesforce.comFor production:
sf org login web -a MyProd -r https://login.salesforce.com# Deploy all metadata
sf project deploy start
# Or deploy specific package
sf project deploy start -d github-action-service# Check deployment status
sf project deploy reportSetup → Custom Metadata Types → GitHub App Settings → Manage Records
Click New and fill in the following:
| Field | Value | Example |
|---|---|---|
| Label | Salesforce GForce DevHub |
Salesforce GForce DevHub |
| Developer Name | salesforce_gforce_devhub |
salesforce_gforce_devhub |
| App ID | Your GitHub App ID | 123456 |
| Installation ID | Your Installation ID | 12345678 |
| Webhook Secret | The webhook secret you generated | a1b2c3d4... |
| Private Key Base64 | Content of private_key_base64.txt |
MIIEvgIBADAN... |
Click Save.
# Assign to current user
sf org assign permset -n GitHub_Integration_Admin
# Or via UI: Setup → Permission Sets → GitHub Integration Admin → Manage AssignmentsEnsure the permission set includes:
- Custom Metadata Type:
GitHub_App_Settings__mdt(Read) - Apex Classes:
GitHubAppAuthService,GitHubActionsService,GitHubWebhookService - Custom Permissions: Any custom permissions created
Setup → Lightning App Builder → New
Or edit an existing page:
App Launcher → [Your App] → Home → Edit Page (gear icon)
- Drag GitHub Action Trigger component from the component list
- Place it in your desired layout section
- Click Save
- Click Activate (if new page)
- Navigate to the page with the LWC component
- Click "Test Connection & List Workflows" button
- Verify you see:
- ✅ Success message
- ✅ List of workflows from your repository
# Start log streaming
sf apex tail log --colorIn another terminal:
# Trigger a test from the UI
# Watch the logs in real-time- Select a workflow from the dropdown
- Enter a branch name (e.g.,
main) - Click "Trigger Workflow"
- Verify:
- ✅ Success toast in Salesforce
- ✅ Workflow appears in GitHub Actions tab
Use curl to test your webhook endpoint:
curl -X POST https://[your-org].my.salesforce.com/services/apexrest/githubwebhook \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: ping" \
-H "X-Hub-Signature-256: sha256=test" \
-d '{"zen": "Keep it simple."}'In GitHub App settings:
- Click Advanced tab
- View Recent Deliveries
- Check for successful deliveries (200 response)
Before going to production, verify:
- GitHub App is configured with correct permissions
- Webhook secret is strong and randomly generated
- Private key is stored securely (consider external secret manager)
- Custom Metadata visibility is set to "Protected"
- Permission set assigned only to necessary users
- Debug logs tested and working
- Webhook deliveries tested and verified
- Error handling tested (wrong credentials, network issues)
- Rate limiting considered (GitHub API has limits)
- Token caching implemented (optional, but recommended)
Recommended every 90 days:
- Generate new private key in GitHub App settings
- Convert to base64
- Update Custom Metadata record
- Revoke old key in GitHub after verifying new key works
- GitHub API rate limits: 5,000 requests/hour for installation tokens
- Monitor via GitHub App settings → Advanced tab
If your Salesforce org URL changes:
- Update webhook URL in GitHub App settings
- Update Named Credential in Salesforce (if needed)
Solution:
- Check Custom Metadata record Developer Name matches:
salesforce_gforce_devhub - Verify Permission Set is assigned
Solution:
- Verify private key is base64 encoded without headers/footers
- Check for extra whitespace or line breaks
- Ensure App ID is correct
Solution:
- Verify App ID matches GitHub App
- Verify Installation ID is correct
- Check GitHub App is installed on target repository
- Verify private key is correct
Solution:
- Verify webhook secret in Custom Metadata matches GitHub App
- Check for typos or extra whitespace
- Ensure webhook secret hasn't been regenerated in GitHub
Solution:
- Verify repository has
.github/workflows/*.ymlfiles - Check GitHub App has Actions permissions
- Verify repository name and owner are correct
This is expected! GitHub App private keys are in PKCS#1/PKCS#8 format, not X.509 certificates.
Why this doesn't work:
GitHub provides: RSA Private Key (PKCS#1)
Salesforce needs: X.509 Certificate with chain
Solution: Use Protected Custom Metadata instead
- Convert key to base64 (as shown in Step 2.2)
- Store in Custom Metadata Type field
- This provides equivalent security without format conversion issues
What happens if you try:
# This will fail:
Setup → Certificate and Key Management → Import Certificate
→ Upload github-app-private-key.pem
❌ Error: "Invalid certificate format" or "Missing certificate chain"Correct approach:
# Convert to base64 for Custom Metadata
cat github-app-private-key.pem | grep -v "BEGIN\|END" | tr -d '\n'
→ Store in Custom Metadata Type: GitHub_App_Settings__mdt
✅ Works perfectly!- GitHub Apps Documentation
- Creating a GitHub App
- Installing GitHub Apps
- Salesforce Named Credentials
- Protected Custom Metadata Types
You've successfully configured the GitHub Actions integration! You can now:
- ✅ Trigger GitHub workflows from Salesforce
- ✅ Receive webhook notifications when workflows complete
- ✅ Use secure JWT-based authentication
- ✅ Monitor all integration activity