| name | source-integrations |
| version | 1.0 |
| description | Set up and maintain GitHub OAuth2 and Slack Bot Token integrations for notification-hub. |
| tools | ["Bash","Read","Write","Edit"] |
source-integrations skill
This skill covers setting up the GitHub and Slack integrations from scratch, including creating the OAuth2 app, configuring credentials, and troubleshooting common sync failures.
GitHub integration
Create the GitHub OAuth App
- Go to GitHub > Settings > Developer settings > OAuth Apps > New OAuth App.
- Fill in:
- Application name:
notification-hub (or any name)
- Homepage URL:
http://localhost:3000
- Authorization callback URL:
http://localhost:3000/auth/github/callback
- Click "Register application".
- Copy the Client ID and generate a Client Secret.
- Set in your environment:
GITHUB_CLIENT_ID=Ov23liXXXXXXXXXX
GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GITHUB_CALLBACK_URL=http://localhost:3000/auth/github/callback
For production replace localhost:3000 with your public URL.
OAuth2 flow (passport-github2)
The flow is handled by src/integrations/github/oauth.ts. The strategy is registered at startup:
GET /auth/github - redirect to GitHub
GET /auth/github/callback - exchange code for token, store encrypted, redirect to /sources
The access token is encrypted with AES-256-GCM before writing to the sources.access_token_enc column:
NOTIFICATION_HUB_ENCRYPTION_KEY must be exactly 64 hex characters (32 bytes)
Generate a key:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
GitHub sync
After connection, the poller in src/integrations/github/sync.ts runs on the SYNC_INTERVAL_MS schedule. It calls:
GET /notifications?all=false&participating=false&since=<last_sync>
Each notification is upserted into the notifications table using the GitHub id field as the external ID to prevent duplicates. Mute rules are evaluated at ingest time.
Configuring watched repositories
After OAuth, the user selects repos in the UI. Only notifications from those repos are stored. Update via API:
curl -X PATCH http://localhost:3000/api/sources/:id \
-H 'Content-Type: application/json' \
-d '{"config": {"repos": ["owner/repo1","owner/repo2"]}}'
Pass an empty array to watch all repos:
curl -X PATCH http://localhost:3000/api/sources/:id \
-H 'Content-Type: application/json' \
-d '{"config": {"repos": []}}'
GitHub notification types
| GitHub reason | Displayed as |
|---|
review_requested | PR review |
mention | Mention |
assign | Issue assignment |
ci_activity | CI status |
subscribed | Subscribed |
team_mention | Team mention |
GitHub troubleshooting
Token expired or revoked
The source status will show error. Disconnect and reconnect via OAuth.
Rate limit hit
GitHub REST API allows 5000 requests/hour for authenticated users. The poller backs off automatically when the X-RateLimit-Remaining header is below 100.
Callback URL mismatch
If GitHub returns redirect_uri_mismatch, the GITHUB_CALLBACK_URL env var must exactly match the callback URL registered in the OAuth App settings.
Slack integration
Create the Slack App
- Go to https://api.slack.com/apps > Create New App > From scratch.
- Name:
notification-hub. Pick your workspace.
- Under OAuth and Permissions > Scopes > Bot Token Scopes, add:
channels:history
channels:read
groups:history
groups:read
users:read
- Click Install to Workspace. Copy the Bot User OAuth Token (
xoxb-...).
- Do NOT set
SLACK_CLIENT_ID/SLACK_CLIENT_SECRET unless you want the full OAuth flow. For a single-workspace personal setup, only the bot token is required.
Connecting with a bot token
In the notification-hub web UI:
- Sources > Add Source > Slack.
- Paste the
xoxb-... token.
- The server calls
auth.test to validate and fetch the workspace info.
- Select channels to watch from the list returned by
conversations.list.
The token is stored encrypted at rest (same AES-256-GCM scheme as GitHub).
Slack sync
src/integrations/slack/sync.ts polls each watched channel using conversations.history with a oldest cursor equal to the last sync timestamp. New messages are stored as notifications. Direct mentions (<@UXXXXXXXX>) are given higher priority automatically.
Configuring watched channels
curl http://localhost:3000/api/sources/:id/channels
curl -X PATCH http://localhost:3000/api/sources/:id \
-H 'Content-Type: application/json' \
-d '{"config": {"channels": ["C012ABCDE","C999FGHIJ"]}}'
Slack troubleshooting
invalid_auth error
The token has been revoked or the app was uninstalled. Generate a new bot token in the Slack app settings and update via disconnect/reconnect.
not_in_channel error
The bot must be invited to private channels. In Slack: /invite @notification-hub in the channel.
Missing messages
conversations.history only returns messages from public channels and private channels where the bot is a member. Threads are fetched separately with conversations.replies if thread_ts is present.
Rate limits
Slack Tier 3 methods (conversations.history) allow ~50 requests/minute. The poller automatically adds delays between channel polls when multiple channels are watched.
Encryption key rotation
If you need to rotate the NOTIFICATION_HUB_ENCRYPTION_KEY:
- Set the new key as
NOTIFICATION_HUB_ENCRYPTION_KEY_NEW.
- Run the migration script:
pnpm run migrate:rotate-keys
This re-encrypts all stored tokens with the new key. After the script completes, rename ENCRYPTION_KEY_NEW to ENCRYPTION_KEY and restart the server.
Testing integrations locally
Use ngrok or a similar tunnel to expose localhost:3000 for OAuth callbacks during development:
ngrok http 3000
Set GITHUB_CALLBACK_URL=https://abc123.ngrok.io/auth/github/callback and update the GitHub OAuth App callback URL to match.