Python Slack Events API adapter for Flask that provides event-driven Slack app development
—
Integration capabilities for incorporating Slack event handling into existing Flask applications, Blueprints, and other WSGI-compatible web frameworks. The SlackServer class handles HTTP request processing, signature verification, and Slack-specific protocol requirements.
Internal Flask server that processes HTTP requests and handles Slack Events API protocol requirements.
class SlackServer(Flask):
def __init__(self, signing_secret, endpoint, emitter, server):
"""
Internal server for handling Slack Events API requests.
Parameters:
- signing_secret: str - Slack app's signing secret
- endpoint: str - URL endpoint for receiving events
- emitter: SlackEventAdapter - Event emitter instance
- server: Flask/Blueprint/LocalProxy or None - Server to bind to
Raises:
- TypeError: If server is not Flask, Blueprint, or LocalProxy instance
"""Binds the Slack event handling route to existing Flask applications or Blueprints.
def bind_route(self, server):
"""
Bind the event handling route to a Flask server or Blueprint.
Parameters:
- server: Flask/Blueprint/LocalProxy - Server instance to bind route to
Returns:
None
"""Verifies incoming request signatures using HMAC-SHA256 to ensure requests are from Slack.
def verify_signature(self, timestamp: str, signature: str) -> bool:
"""
Verify the request signature using the app's signing secret.
Parameters:
- timestamp: str - Request timestamp from X-Slack-Request-Timestamp header
- signature: str - Request signature from X-Slack-Signature header
Returns:
bool - True if signature is valid, False otherwise
"""Generates user-agent information for HTTP response headers.
def get_package_info(self) -> str:
"""
Collect package version and system information for user-agent.
Returns:
str - Formatted user-agent string containing client, Python, and system versions
"""The SlackServer instance (accessible via adapter.server) provides access to internal state and configuration.
signing_secret: str
"""The signing secret used for HMAC signature verification."""
emitter: SlackEventAdapter
"""Reference to the parent SlackEventAdapter instance."""
endpoint: str
"""The URL endpoint configured for receiving Slack events."""
package_info: str
"""User-agent string containing package version and system information."""The SlackServer automatically handles several aspects of Slack Events API requests:
When Slack sends a challenge request to verify your endpoint:
{
"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"
}The server automatically responds with the challenge value to complete verification.
For actual events, the server:
import os
from flask import Flask
from slackeventsapi import SlackEventAdapter
# Create your Flask app
app = Flask(__name__)
# Add your existing routes
@app.route("/health")
def health_check():
return {"status": "healthy"}
@app.route("/api/data")
def get_data():
return {"data": "example"}
# Integrate Slack events
slack_events_adapter = SlackEventAdapter(
signing_secret=os.environ["SLACK_SIGNING_SECRET"],
endpoint="/api/slack/events", # Custom endpoint
server=app # Bind to existing app
)
@slack_events_adapter.on("message")
def handle_message(event_data):
event = event_data["event"]
print(f"Message: {event.get('text', '')}")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)import os
from flask import Blueprint
from slackeventsapi import SlackEventAdapter
# Create a Blueprint
slack_bp = Blueprint('slack', __name__, url_prefix='/slack')
# Add routes to the Blueprint
@slack_bp.route('/status')
def slack_status():
return {"slack": "active"}
# Bind Slack events to the Blueprint
slack_events_adapter = SlackEventAdapter(
signing_secret=os.environ["SLACK_SIGNING_SECRET"],
endpoint="/events", # Will be /slack/events due to Blueprint prefix
server=slack_bp
)
@slack_events_adapter.on("reaction_added")
def handle_reaction(event_data):
event = event_data["event"]
print(f"Reaction: {event['reaction']}")
# Register Blueprint with main app
from flask import Flask
app = Flask(__name__)
app.register_blueprint(slack_bp)import os
from flask import Flask
from slackeventsapi import SlackEventAdapter
app = Flask(__name__)
# Production events
prod_adapter = SlackEventAdapter(
signing_secret=os.environ["SLACK_SIGNING_SECRET_PROD"],
endpoint="/slack/prod/events",
server=app
)
# Development events
dev_adapter = SlackEventAdapter(
signing_secret=os.environ["SLACK_SIGNING_SECRET_DEV"],
endpoint="/slack/dev/events",
server=app
)
@prod_adapter.on("message")
def handle_prod_message(event_data):
print("Production message received")
@dev_adapter.on("message")
def handle_dev_message(event_data):
print("Development message received")import os
from flask import Flask
from slackeventsapi import SlackEventAdapter
from slackeventsapi.server import SlackEventAdapterException
app = Flask(__name__)
slack_events_adapter = SlackEventAdapter(
signing_secret=os.environ["SLACK_SIGNING_SECRET"],
endpoint="/slack/events",
server=app
)
@slack_events_adapter.on("error")
def handle_slack_error(error):
if isinstance(error, SlackEventAdapterException):
error_msg = str(error)
if "Invalid request signature" in error_msg:
print("WARNING: Invalid signature - check signing secret")
# Could log to monitoring service
elif "Invalid request timestamp" in error_msg:
print("WARNING: Old timestamp - possible replay attack or clock skew")
# Could implement additional logging
else:
print(f"Unexpected error: {error}")
# Your app routes
@app.route("/")
def index():
return "Slack Events API Integration"
if __name__ == "__main__":
app.run(debug=True)import os
from flask import Flask
from slackeventsapi import SlackEventAdapter
app = Flask(__name__)
# Create adapter
slack_events_adapter = SlackEventAdapter(
signing_secret=os.environ["SLACK_SIGNING_SECRET"],
endpoint="/slack/events",
server=app
)
# Access server attributes for monitoring or debugging
print(f"Server endpoint: {slack_events_adapter.server.endpoint}")
print(f"Package info: {slack_events_adapter.server.package_info}")
print(f"Signing secret configured: {'Yes' if slack_events_adapter.server.signing_secret else 'No'}")
@app.route("/status")
def status():
return {
"endpoint": slack_events_adapter.server.endpoint,
"package_info": slack_events_adapter.server.package_info
}
if __name__ == "__main__":
app.run()All incoming requests are automatically verified using HMAC-SHA256 with your signing secret. Invalid signatures result in HTTP 403 responses and "error" event emission.
Requests older than 5 minutes are rejected to prevent replay attacks. This protects against malicious actors replaying captured requests.
The server adds X-Slack-Powered-By headers to successful responses containing package version information for debugging and monitoring.
Install with Tessl CLI
npx tessl i tessl/pypi-slackeventsapi