Skip to content

feat: implement mobile money callback signature verification#150

Open
elijah4196 wants to merge 1 commit into
Pidoko257:mainfrom
elijah4196:feat/mobile-money-callback-signature-verification-105
Open

feat: implement mobile money callback signature verification#150
elijah4196 wants to merge 1 commit into
Pidoko257:mainfrom
elijah4196:feat/mobile-money-callback-signature-verification-105

Conversation

@elijah4196

Copy link
Copy Markdown

feat: implement mobile money callback signature verification (#105)

Summary

Adds provider-specific callback signature verification for MTN MoMo and Airtel Money inbound webhook callbacks. Unverified callbacks are rejected with HTTP 403 and logged as security anomaly events.

Changes

MTN MoMo (src/middleware/mtnCallbackSignature.ts)

  • Fixed response code: unverified callbacks now return 403 Forbidden (was 401) per acceptance criteria
  • HMAC-SHA256 verification using MTN_CALLBACK_SECRET (subscription key) on the X-Callback-Signature header
  • Supports both sha256= prefixed hex and plain base64 signature formats
  • Timing-safe comparison via timingSafeEqual
  • All rejection paths log a security.anomaly event with reason code

Airtel Money — new

File Description
src/middleware/airtelCallbackSignature.ts New middleware — validates Authorization: Bearer {token} against AIRTEL_CALLBACK_SECRET using timingSafeEqual. Missing = 403. Invalid = 403. Unconfigured = 500. All failures logged as security anomalies.
src/routes/airtelCallbacks.ts New router — ingestRateLimiterverifyAirtelCallbackSignaturePOST /callback{ status: "accepted" }
src/config/appConfig.ts Added providers.airtel.callbackSecret config entry (env: AIRTEL_CALLBACK_SECRET)
src/index.ts Mounted Airtel callback router at app.use("/api/airtel", airtelCallbacksRouter)

Tests

File Tests
src/middleware/__tests__/airtelCallbackSignature.test.ts 5 unit tests: unconfigured secret (500), missing header (403), non-Bearer scheme (403), valid token (200), wrong token (403)
src/routes/__tests__/airtelCallbacks.test.ts 4 integration tests via supertest: valid bearer (200), missing auth (403), wrong token (403), Basic scheme (403)
src/middleware/__tests__/mtnCallbackSignature.test.ts Updated — expect 403 instead of 401
src/routes/__tests__/mtnCallbacks.test.ts Updated — expect 403 instead of 401

Environment Variables Required

MTN_CALLBACK_SECRET=<mtn-subscription-key-or-hmac-secret>
AIRTEL_CALLBACK_SECRET=<airtel-shared-secret-token>

Acceptance Criteria

  • ✅ MTN MoMo callbacks validate X-Callback-Signature header using HMAC-SHA256 with subscription key
  • ✅ Airtel callbacks validate Authorization: Bearer token against expected shared secret
  • ✅ Unverified callbacks return 403 and are logged as security events
  • ✅ Verification logic is unit tested with known valid and invalid signature vectors

closes #105

…57#105)

- Fix MTN callback: unverified callbacks now return 403 (was 401)
- Add Airtel callback Bearer token verification middleware
- Add Airtel callback route at /api/airtel with rate limiting
- Add AIRTEL_CALLBACK_SECRET config entry in appConfig
- Mount Airtel callback router in index.ts
- Add unit tests for Airtel signature middleware (5 tests)
- Add integration tests for Airtel callback route (4 tests)
- Update MTN tests to expect 403

closes Pidoko257#105
@drips-wave

drips-wave Bot commented Jun 30, 2026

Copy link
Copy Markdown

@elijah4196 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Mobile Money Callback Signature Verification

2 participants