Automates Slack app install request intake for enterprise Slack workspaces. Automatically creates Jira Service Management tickets for every app request, posts a risk assessment based on OAuth scopes, and notifies requesters with ticket details.
triggers/
new_request_trigger.ts — Real-time: fires on new USLACKBOT messages
reaction_trigger.ts — Retroactive: fires on :ticket: reaction
app_requested_trigger.ts — (parked: not supported by Deno platform)
workflows/
new_request_workflow.ts — Real-time: parse → ticket → risk comment → notify
emoji_ticket_workflow.ts — Retroactive: parse → ticket → risk comment → notify
app_request_workflow.ts — (parked: for app_requested event)
functions/
parse_app_request.ts — Parse app_requested event payload
parse_channel_message.ts — Fetch + parse Slackbot message (shared by both active paths)
create_app_request_ticket.ts — Create Jira JSM ticket
evaluate_risk.ts — OAuth scope risk classification (121 scopes, 5 tiers)
post_risk_comment.ts — Post risk assessment as Jira comment
known_apps.ts — Known app database (internal/external classification)
notify_requester.ts — Threaded reply + requester ephemeral with ticket link
tests/
parse_app_request_test.ts — 5 tests for event payload parsing
parse_channel_message_test.ts — 16 tests for Slackbot message parsing
evaluate_risk_test.ts — 17 tests for risk scoring
known_apps_test.ts — 13 tests for request type detection
manifest.ts — App manifest
Every request is classified using a hardcoded known apps database populated from your Slack admin export. Apps not in the database default to Internal New.
| Type | Detection | Routing |
|---|---|---|
| Workflow Builder | Message: "steps in Workflow Builder" | Normal approval |
| Internal New | Known app (internal) or not in map | Normal approval |
| Internal Upgrade | "previously approved" + internal app | Normal approval |
| External New (Known) | Known app (app_directory) | Normal approval |
| External Upgrade | "previously approved" + external app | Normal approval |
Classification is map-only. Slack's "not approved by Slack" flag and marketplace
URLs appear on all new apps regardless of whether they are internal or external,
so they are not reliable detection signals. Populate known_apps.ts with your
org's app export to drive classification.
Path 1 — Real-time (active): When a new USLACKBOT app request message appears in your app requests channel, the bot automatically parses it, creates a Jira ticket, posts a threaded reply, and sends an ephemeral confirmation to the requester.
Path 2 — Retroactive (active): React with :ticket: on any existing
Slackbot app request message. The bot creates a Jira ticket and posts a threaded
reply. Useful for backfilling requests that predate the bot and for testing.
Path 3 — Event-driven (parked): app_requested event trigger is not
supported by Slack's hosted Deno platform. Code exists but the trigger cannot be
created.
- Slack CLI (
slackcommand) - deno-slack-sdk v2.15.1 (pinned in
deno.jsonc) - Deno runtime (installed automatically by Slack CLI)
- Jira Cloud with a JSM service desk project
Update the hardcoded values in source before deploying:
| Value | Location | What to set |
|---|---|---|
JIRA_BASE_URL |
create_app_request_ticket.ts, post_risk_comment.ts |
Your Jira Cloud base URL |
SERVICE_DESK_ID |
create_app_request_ticket.ts |
Your JSM service desk ID |
REQUEST_TYPE_ID |
create_app_request_ticket.ts |
Your JSM request type ID |
ALERT_CHANNEL_ID |
notify_requester.ts, create_app_request_ticket.ts, parse_channel_message.ts, parse_app_request.ts |
Channel ID for your app requests channel |
channel_ids |
reaction_trigger.ts, new_request_trigger.ts |
Channel ID for your app requests channel |
functions/known_apps.ts contains a map of known Slack apps keyed by app ID
with a source field: "internal" for apps built by your org,
"app_directory" for third-party apps from Slack's App Directory.
Export your installed apps from Slack Admin, classify each entry, and populate
the map. Apps not in the map default to Internal New at classification time.
slack env add JIRA_API_EMAIL <service-account-email>
slack env add JIRA_API_TOKEN <api-token>
slack deploy# Real-time — fires on new USLACKBOT messages in your app requests channel
slack trigger create --trigger-def triggers/new_request_trigger.ts
# Retroactive — fires on :ticket: reaction
slack trigger create --trigger-def triggers/reaction_trigger.tsThe bot must be a member of your app requests channel for both triggers to work.
Invite it with /invite @Your Bot Name in the channel.
slack env add JIRA_API_EMAIL <service-account-email>
slack env add JIRA_API_TOKEN <api-token>All other configuration is hardcoded in source (see Setup above). Secrets never
go in code — use slack env add exclusively.
slack runTicket creation uses the JSM servicedeskapi/request endpoint, not the standard
/rest/api/3/issue endpoint. Using the standard API creates the ticket but
leaves the Request Type field empty. The JSM endpoint requires the
X-ExperimentalApi: opt-in header.
| Field | Value |
|---|---|
| Summary | Slack App Request (Type) - {app_name} - requested by {user} |
| Reporter | The Slack user who requested the app (via raiseOnBehalfOf) |
| Assignee | None (goes to open queue) |
| API | JSM POST /rest/servicedeskapi/request |
If the requester's email is not a Jira customer, the ticket is created under the service account with an attribution note in the description.
To find your service desk ID and request type ID:
GET https://your-org.atlassian.net/rest/servicedeskapi/servicedesk
GET https://your-org.atlassian.net/rest/servicedeskapi/servicedesk/{id}/requesttype
The bot parses two Slackbot message formats:
- Standard install:
@user would like to install the app AppName on the workspace YourWorkspace - Workflow Builder:
@user would like to use AppName steps in Workflow Builder
Both workspace-level and organization-level requests are supported.
After creating a Jira ticket, the bot posts a risk assessment comment based on the app's requested OAuth scopes. 121 Slack OAuth scopes are classified across 5 tiers.
The comment includes:
- Total risk score and overall tier
- Scopes grouped by risk tier (Restricted, High, Medium, Low, Safe)
- Human-readable description for each scope
- Recommendation for reviewers
Risk tiers and thresholds:
| Tier | Score | Action |
|---|---|---|
| Restricted | 10/scope | Any admin.* scope — requires security review |
| High Risk | 5/scope | Route to security review |
| Medium Risk | 3/scope | Manual review recommended |
| Low Risk | 1/scope | Auto-approve eligible (internal apps) |
| Safe | 0/scope | Auto-approve |
Decision thresholds: Score 0–3 = Low risk, 4–10 = Medium risk, >10 = High risk, any Restricted scope = Restricted regardless of total score.
The emoji trigger checks the message thread before creating a ticket. If a threaded reply from the bot already exists, the workflow halts without creating a duplicate ticket.
deno task test51 tests total (5 event parsing + 16 channel message parsing + 17 risk scoring + 13 request type detection).
- Auto-approve low-risk internal apps
- Jira custom field population (risk score, flags as structured fields)
/app-requestslash command + Block Kit modal- Periodic refresh of known apps database from Slack admin export
- AI-powered recommendations (LLM analysis of scope combinations)