{"id":16061084,"url":"https://github.com/amancevice/terraform-aws-slackbot","last_synced_at":"2026-02-04T22:18:14.495Z","repository":{"id":37498884,"uuid":"138161712","full_name":"amancevice/terraform-aws-slackbot","owner":"amancevice","description":"Serverless Extensible Slackbot","archived":false,"fork":false,"pushed_at":"2025-03-06T14:03:37.000Z","size":17961,"stargazers_count":88,"open_issues_count":1,"forks_count":25,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-30T04:08:47.262Z","etag":null,"topics":["aws","nodejs","serverless","slack","terraform"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/amancevice.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-06-21T11:30:49.000Z","updated_at":"2025-03-15T17:19:52.000Z","dependencies_parsed_at":"2024-04-06T15:31:54.220Z","dependency_job_id":"de617e3f-6788-4866-a3c2-0fa51173f96f","html_url":"https://github.com/amancevice/terraform-aws-slackbot","commit_stats":{"total_commits":283,"total_committers":3,"mean_commits":94.33333333333333,"dds":0.3992932862190812,"last_synced_commit":"244ac30788eff79466ed952f260ef4862f876828"},"previous_names":[],"tags_count":144,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amancevice%2Fterraform-aws-slackbot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amancevice%2Fterraform-aws-slackbot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amancevice%2Fterraform-aws-slackbot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/amancevice%2Fterraform-aws-slackbot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/amancevice","download_url":"https://codeload.github.com/amancevice/terraform-aws-slackbot/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247436286,"owners_count":20938533,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","nodejs","serverless","slack","terraform"],"created_at":"2024-10-09T04:07:48.425Z","updated_at":"2026-02-04T22:18:09.472Z","avatar_url":"https://github.com/amancevice.png","language":"Python","funding_links":["https://ko-fi.com/smallweirdnumber"],"categories":[],"sub_categories":[],"readme":"# Serverless Slackbot\n\n![arch](./docs/arch.png)\n\n[![terraform](https://img.shields.io/github/v/tag/amancevice/terraform-aws-slackbot?color=62f\u0026label=version\u0026logo=terraform\u0026style=flat-square)](https://registry.terraform.io/modules/amancevice/slackbot/aws)\n[![build](https://img.shields.io/github/actions/workflow/status/amancevice/terraform-aws-slackbot/test-validate.yml?logo=github\u0026style=flat-square)](https://github.com/amancevice/terraform-aws-slackbot/actions/workflows/test-validate.yml)\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/smallweirdnumber)\n\nA simple, serverless back end for your Slack app.\n\n\u003e ⚠️ NOTE — `v25` of this module is a complete architectural redesign and is not compatible with previous versions.\n\n## Use Case\n\nThe application intentionally does very little, leaving room for you to customize your app.\n\nOut of the box, it will:\n\n- Receive an event from Slack in the form of an HTTP request\n- Verify the request's signature headers\n- Publish the JSON-ified payload to EventBridge where it can be processed asynchronously\n- And, finally, send a response back to Slack (usually an empty 200)\n\nAdding asynchronous features to your slackbot is as simple as adding the appropriate EventBridge rule/target, and some kind of handler function. See the section on [responding to events asynchronously](#responding-to-events-asynchronously) for details. See the [EventBridge documentation](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html) for more info on event pattern matching.\n\nIn some cases, you may want your Slack app to send a custom, synchronous, response to Slack instead of an empty `200` OK. External select menus and some callbacks, for example, need to respond to Slack with custom data and cannot be processed asyncronously. See the section on [responding to events synchronously](#responding-to-events-synchronously) for details.\n\n## Prerequisites\n\nBefore applying this module you should have created the following resources:\n\n- Route53 Hosted Zone (eg, `example.com`)\n- An available subdomain for your app's REST API (eg, `slack.example.com`)\n- ACM Certificate covering your app's subdomain (eg, `*.example.com`, `slack.example.com`)\n- A [Slack App](https://api.slack.com/apps) with a signing secret, OAuth client keys, and a default web API token\n\n## SnapStart\n\nAWS Lambda supports [SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) for functions using Python v3.12+ or greater.\n\nEnabling SnapStart will improve (decrease) the latency for your app's HTTP responses but it is not free, so it is disabled by default.\n\n## Example Usage\n\nSee the [example](./example) project for detailed usage.\n\n```terraform\ndata \"aws_acm_certificate\" \"cert\" {\n  domain = \"example.com\"\n  types  = [\"AMAZON_ISSUED\"]\n}\n\ndata \"aws_route53_zone\" \"zone\" {\n  name = \"example.com.\"\n}\n\nmodule \"slackbot\" {\n  source  = \"amancevice/slackbot/aws\"\n  version = \"~\u003e 25.0\"\n\n  # App Name\n  name = \"slackbot\"\n\n  # DNS\n  domain_name            = \"slack.example.com\"\n  domain_certificate_arn = data.aws_acm_certificate.cert.arn\n  domain_zone_id         = data.aws_route53_zone.zone.id\n\n  # LAMBDA CONFIG\n  lambda_snap_start_enabled = true\n\n  # SLACK\n  slack_client_id      = var.slack_client_id\n  slack_client_secret  = var.slack_client_secret\n  slack_error_uri      = \"https://example.com/slack/error.html\"\n  slack_scope          = \"app_mentions:read,chat:write\"\n  slack_signing_secret = var.slack_signing_secret\n  slack_success_uri    = \"slack://app?team={TEAM_ID}\u0026id={APP_ID}\"\n  slack_user_scope     = \"\"\n  slack_token          = var.slack_token\n\n  # TAGS\n  tags = {\n    # ...\n  }\n}\n```\n\n## HTTP Routes\n\nEndpoints are provided for the following routes:\n\n| Route            | Event Published? | Custom Response? | Purpose                                                                                                  |\n| :--------------- | ---------------: | ---------------: | :------------------------------------------------------------------------------------------------------- |\n| `GET /install`   |             `No` |             `No` | Helper to begin Slack's OAuth flow                                                                       |\n| `GET /oauth`     |            `Yes` |             `No` | Complete Slack's [OAuth2](https://api.slack.com/docs/oauth) workflow (v2)                                |\n| `POST /callback` |            `Yes` |            `Yes` | Handle Slack's [interactive messages](https://api.slack.com/messaging/interactivity)                     |\n| `POST /event`    |            `Yes` |             `No` | Handle events from Slack's [Events API](https://api.slack.com/events-api)                                |\n| `POST /menu`     |            `Yes` |            `Yes` | Handle [external select menus](https://api.slack.com/reference/block-kit/block-elements#external_select) |\n| `POST /slash`    |            `Yes` |            `Yes` | Handle Slack's [slash commands](https://api.slack.com/slash-commands)                                    |\n\n## Responding to Events Synchronously\n\nFor some events (external select menus, for example) you will need to respond to Slack with a JSON payload.\nThis can be accomplished by deploying a specially named Lambda function that returns a proxy-like response.\n\nWhen your app receives an event that supports a synchronous response it will attempt to call a Lambda function with the naming convention:\n\n```plaintext\n\u003cyour-app-name\u003e-\u003cslack-event-type\u003e\n```\n\nThis function should return a JSON object with `statusCode` and `body` fields.\nThe `statusCode` field should be `200` and the `body` field should be the response payload encoded as a JSON string.\n\n### Example Synchronous Function\n\nThe following Python block is a crude example of a Lambda function that provides options for an external menu:\n\n```python\nimport json\n\ndef handler(event, _):\n    return {\n        \"statusCode\": 200,\n        \"body\": json.dumps({\n            \"options\": [\n                {\"value\": \"option1\", \"text\": {\"type\": \"plain_text\", \"text\": \"Option 1\"}},\n                {\"value\": \"option2\", \"text\": {\"type\": \"plain_text\", \"text\": \"Option 2\"}},\n                {\"value\": \"option3\", \"text\": {\"type\": \"plain_text\", \"text\": \"Option 2\"}},\n            ]\n        }),\n    }\n```\n\nAssuming our app is named `slackbot` we would then deploy this function with the name `slackbot-block_suggestion` since it is intended to be invoked for Slack events with the type of `block_suggestion`.\n\nSee the [example](./example) project for more advanced usage.\n\n## Responding to Events Asynchronously\n\nEventBridge events are actionable through [event patterns](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns.html).\nYou can filter events using a bus name, source value, detail-type, and even parts of the event payload.\n\nThe following table shows the mapping of route-key : event\n\n| Route Key        | Event Bus    | Source          | Detail Type      |\n| :--------------- | :----------- | :-------------- | :--------------- |\n| `GET /oauth`     | `\u003cyour-app\u003e` | `\u003cyour-domain\u003e` | `GET /oauth`     |\n| `POST /callback` | `\u003cyour-app\u003e` | `\u003cyour-domain\u003e` | `POST /callback` |\n| `POST /event`    | `\u003cyour-app\u003e` | `\u003cyour-domain\u003e` | `POST /event`    |\n| `POST /menu`     | `\u003cyour-app\u003e` | `\u003cyour-domain\u003e` | `POST /menu`     |\n| `POST /slash`    | `\u003cyour-app\u003e` | `\u003cyour-domain\u003e` | `POST /slash`    |\n\n### Example Event Patterns\n\nIn order to process a given event you will need to create an EventBridge rule with a pattern that targets a specific event.\n\nThe following examples show how a subscription might me made in Terraform:\n\n#### Callbacks\n\n```terraform\nresource \"aws_cloudwatch_event_rule\" \"block_actions\" {\n  event_bus_name = \"\u003cyour-app\u003e\"\n  # …\n\n  event_pattern = jsonencode({\n    source      = [\"\u003cyour-domain\u003e\"]\n    detail-type = [\"POST /callback\"]\n    detail = {\n      type = [\"block_actions\"]\n      actions = {\n        action_id = [\"your_action_id\"]\n      }\n    }\n  })\n}\n```\n\n```terraform\nresource \"aws_cloudwatch_event_rule\" \"view_submission\" {\n  event_bus_name = \"\u003cyour-app\u003e\"\n  # …\n\n  event_pattern = jsonencode({\n    source      = [\"\u003cyour-domain\u003e\"]\n    detail-type = [\"POST /callback\"]\n    detail = {\n      type = [\"view_submission\"]\n      view = {\n        callback_id = [\"your_view_callback_id\"]\n      }\n    }\n  })\n}\n```\n\n#### Event\n\n```terraform\nresource \"aws_cloudwatch_event_rule\" \"app_home_opened\" {\n  event_bus_name = \"\u003cyour-app\u003e\"\n  # …\n\n  event_pattern = jsonencode({\n    source      = [\"\u003cyour-domain\u003e\"]\n    detail-type = [\"POST /callback\"]\n    detail = {\n      type = [\"event_callback\"]\n      event = {\n        type = [\"app_home_opened\"]\n      }\n    }\n  })\n}\n```\n\n#### OAuth\n\n```terraform\nresource \"aws_cloudwatch_event_rule\" \"oauth\" {\n  event_bus_name = \"\u003cyour-app\u003e\"\n  # …\n\n  event_pattern = jsonencode({\n    source      = [\"\u003cyour-domain\u003e\"]\n    detail-type = [\"GET /oauth\"]\n  })\n}\n```\n\n#### Slash Command\n\n```terraform\nresource \"aws_cloudwatch_event_rule\" \"slash\" {\n  event_bus_name = \"\u003cyour-app\u003e\"\n  # …\n\n  event_pattern = jsonencode({\n    source      = [\"\u003cyour-domain\u003e\"]\n    detail-type = [\"POST /slash\"]\n    detail = {\n      type    = [\"slash_command\"]\n      command = [\"/your-command\"]\n    }\n  })\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famancevice%2Fterraform-aws-slackbot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famancevice%2Fterraform-aws-slackbot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famancevice%2Fterraform-aws-slackbot/lists"}