custom action to send approval request to Slack
- Post a message in Slack with a "Aoorove" and "Reject" buttons.
- Clicking on "Approve" will execute next steps.
- Clicking on "Reject" will cause workflow to fail.
- First, create a Slack App and install in your workspace.
- Second, add
chat:writeandim:writeto OAuth Scope on OAuth & Permissions page. - Finally, Enable Socket Mode.
jobs:
approval:
runs-on: ubuntu-latest
steps:
- name: send approval
uses: varu3/slack-approval@main
env:
SLACK_APP_TOKEN: ${{ secrets.SLACK_APP_TOKEN }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
timeout-minutes: 10-
Set environment variables
-
SLACK_APP_TOKEN- App-level tokens on
Basic Information page. (starting withxapp-)
- App-level tokens on
-
SLACK_BOT_TOKEN- Bot-level tokens on
OAuth & Permissions page. (starting withxoxb-)
- Bot-level tokens on
-
SLACK_SIGNING_SECRET- Signing Secret on
Basic Information page.
- Signing Secret on
-
SLACK_CHANNEL_ID- Channel ID for which you want to send approval.
-
-
Set
timeout-minutes- Set the time to wait for approval. If the timeout is reached, GitHub Actions will forcefully terminate the workflow.
You can add custom blocks to the Slack notification by using the custom-blocks input:
jobs:
approval:
runs-on: ubuntu-latest
steps:
- name: send approval
uses: varu3/slack-approval@main
with:
custom-blocks: |
[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Environment:* Production"
}
}
]
env:
SLACK_APP_TOKEN: ${{ secrets.SLACK_APP_TOKEN }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
timeout-minutes: 10The custom blocks will be displayed after the workflow information and before the Approve/Reject buttons. You can use any valid Slack Block Kit blocks.
If you want to completely replace the default workflow information with your own custom blocks (while keeping the Approve/Reject buttons), use the override-base-blocks input:
jobs:
approval:
runs-on: ubuntu-latest
steps:
- name: send approval
uses: varu3/slack-approval@main
with:
override-base-blocks: true
custom-blocks: |
[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Custom Approval Request*"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Environment:*\nProduction"
},
{
"type": "mrkdwn",
"text": "*Requested by:*\n${{ github.actor }}"
}
]
}
]
env:
SLACK_APP_TOKEN: ${{ secrets.SLACK_APP_TOKEN }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
timeout-minutes: 10When override-base-blocks is set to true, only your custom blocks and the Approve/Reject buttons will be displayed. The default workflow information (GitHub Actor, Repository, Actions URL, etc.) will be omitted.
When the timeout-minutes limit is reached, the action automatically:
- Detects the timeout signal from GitHub Actions
- Disables the Approve/Reject buttons in the Slack message
- Updates the message with a timeout notification
- Exits with failure status
The Slack message will be updated to show:
⏱️ Timeout: The approval time has expired and the deployment was cancelled
Example:
jobs:
approval:
runs-on: ubuntu-latest
steps:
- name: send approval
uses: varu3/slack-approval@main
env:
SLACK_APP_TOKEN: ${{ secrets.SLACK_APP_TOKEN }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
timeout-minutes: 10 # Timeout after 10 minutesNote: No additional Slack OAuth scopes are required for timeout handling. The action stores message blocks locally and does not need to fetch the message from Slack API.
Control the verbosity of Slack Bolt framework logs using environment variables:
Priority (highest to lowest):
RUNNER_DEBUG=1- GitHub Actions debug mode (uses DEBUG level)SLACK_LOG_LEVEL- Explicit log level (DEBUG, INFO, WARN, ERROR)- Default:
WARN
Example with explicit log level:
- name: send approval
uses: varu3/slack-approval@main
env:
SLACK_LOG_LEVEL: DEBUG
SLACK_APP_TOKEN: ${{ secrets.SLACK_APP_TOKEN }}
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
SLACK_SIGNING_SECRET: ${{ secrets.SLACK_SIGNING_SECRET }}
SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}Example with GitHub Actions debug mode:
Enable debug mode by setting the ACTIONS_STEP_DEBUG secret to true in your repository settings, or by re-running the workflow with debug logging enabled. The action will automatically use DEBUG log level.
The action provides clear output messages for each outcome:
✅ APPROVED by username (U12345678) at 2025-11-05T12:34:56.789Z
❌ REJECTED by username (U12345678) at 2025-11-05T12:34:56.789Z
⏱️ TIMEOUT - No response received at 2025-11-05T12:34:56.789Z
Slack message updated with timeout notification
All messages include:
- Username and User ID from Slack
- ISO 8601 timestamp of the action
