İçeriğe geç

Twilio Auth Token Rotation — Operasyonel Prosedür

Detay

Proje: ecutuningportal.com (Next.js + Prisma + PM2)
Kapsam: TWILIO_AUTH_TOKEN webhook signature validation rotasyonu
Tahmini süre: 15-20 dakika
Downtime riski: Dual-token stratejisiyle sıfıra yakın


  • Her 90 günde bir rutin olarak (takvime ekle, bekleme yapma)
  • Secret bir yere sızdıysa veya sızma şüphesi varsa — anında
  • Token’a erişimi olan bir çalışan ayrıldıysa — o gün
  • .env dosyası yanlışlıkla version control’a commit edildiyse — anında
  • Twilio hesabında yetkisiz API aktivitesi tespit edildiyse — anında

Twilio bir webhook isteği gönderdiğinde isteği yeni token ile imzalar. Eğer sunucuda hâlâ eski token ile validate ediyorsak, Twilio’nun yeni imzasını reddederiz → 403 → Twilio retry → SMS/voice olayları kaybolur.

Pencere boyutu: Twilio’da primary token rotate edildiği andan sunucu yeni token ile yeniden başlatılana kadar geçen süre — yaklaşık 1-3 dakika.

Eski token’ı silmeden önce kod tarafında hem eski hem yeni token’ı aynı anda kabul et. Önce yeni token deploy edilir, sonra Twilio Console’da eski token invalidate edilir. Bu sırayla yapılırsa sıfır signature mismatch.

Timeline:
t=0 → Twilio'dan yeni token al, env'e TWILIO_AUTH_TOKEN_NEW olarak ekle
t=1 → Dual-token kodu deploy et, PM2 restart
t=2 → Twilio Console'da eski token'ı invalidate et
t=10 → Dual-token kodu kaldır, single token'a dön
t=11 → Tekrar build + restart

  1. console.twilio.comAccountAPI keys & tokens
  2. Auth Tokens bölümünde Secondary Auth Token oluştur (yoksa “Create” butonu)
  3. Yeni Secondary token’ı kopyala — bu rotasyon boyunca TWILIO_AUTH_TOKEN_NEW olacak
  4. Primary token’ı şimdi invalidate ETME — bunu Adım 5’e kadar bekliyoruz

Not: Twilio bazı planlarda Secondary token üretmez. Bu durumda Primary’yi rotate et ama hemen aşağıdaki dual-token deployment’ı yapana kadar invalidate etme.

Adım 2 — .env Dosyasını Güncelle (Eski Token Korunsun)

Bölüm başlığı “Adım 2 — .env Dosyasını Güncelle (Eski Token Korunsun)”
Terminal window
# Production sunucusunda (root veya sudo erişimi gerekli)
nano /var/www/vhosts/ecutuningportal.com/httpdocs/.env

Eski satırı silme, yanına yeni satır ekle:

TWILIO_AUTH_TOKEN=eski_token_degeri # <-- DOKUNMA
TWILIO_AUTH_TOKEN_NEW=yeni_token_degeri_buraya

Dosyayı kaydet.

Adım 3 — Webhook Validation Kodunu Dual-Token Mode’a Al

Bölüm başlığı “Adım 3 — Webhook Validation Kodunu Dual-Token Mode’a Al”

Projede Twilio webhook’u validate eden fonksiyonu bul:

Terminal window
grep -rn "validateRequest\|TWILIO_AUTH_TOKEN\|twilioSignature" \
/var/www/vhosts/ecutuningportal.com/httpdocs/src \
/var/www/vhosts/ecutuningportal.com/httpdocs/app \
/var/www/vhosts/ecutuningportal.com/httpdocs/lib \
--include="*.ts" --include="*.js" -l

Validation mantığını şu pattern’e çevir:

import twilio from 'twilio';
function validateTwilioSignature(
signature: string,
url: string,
params: Record<string, string>
): boolean {
const oldToken = process.env.TWILIO_AUTH_TOKEN!;
const newToken = process.env.TWILIO_AUTH_TOKEN_NEW;
const validWithOld = twilio.validateRequest(oldToken, signature, url, params);
// Yeni token tanımlıysa dual-token mode aktif
if (newToken) {
const validWithNew = twilio.validateRequest(newToken, signature, url, params);
return validWithOld || validWithNew;
}
return validWithOld;
}

Kodu düzenledikten sonra kaydet.

Terminal window
cd /var/www/vhosts/ecutuningportal.com/httpdocs
# Build (yigit user olarak veya chown sonrası)
npm run build
# Dosya sahipliğini düzelt
chown -R yigit:yigit .next/ .env
# PM2 restart
pm2 restart ecutuningportal

PM2 log’larında hata yoksa onayla:

Terminal window
pm2 logs ecutuningportal --lines 30 --nostream

Adım 5 — Eski Token’ı Twilio Console’da Invalidate Et

Bölüm başlığı “Adım 5 — Eski Token’ı Twilio Console’da Invalidate Et”

Bu adımı Adım 4 tamamlanmadan yapma. Dual-token deploy’u kesinleştikten sonra:

  1. Twilio Console → AccountAPI keys & tokens
  2. Primary Auth TokenRotate (veya Secondary’yi Primary’ye promote et)
  3. Eski Primary token’ı invalidate et

Artık Twilio tüm webhook’ları yeni token ile imzalıyor. Sunucu dual-token mode’da olduğu için her ikisini de kabul ediyor.

Adım 6 — 5-10 Dakika Bekle, Sonra Dual-Token’ı Kaldır

Bölüm başlığı “Adım 6 — 5-10 Dakika Bekle, Sonra Dual-Token’ı Kaldır”

Twilio’nun aktif retry kuyruğunda hâlâ eski token ile imzalanmış istek kalmış olabilir. 5-10 dakika beklemek bu pencereyi kapatır.

Ardından .env’i tekrar düzenle:

Terminal window
nano /var/www/vhosts/ecutuningportal.com/httpdocs/.env
TWILIO_AUTH_TOKEN=yeni_token_degeri # artık bu tek token
# TWILIO_AUTH_TOKEN_NEW satırını tamamen sil

Webhook validation kodundan dual-token mantığını kaldır, single token’a dön:

function validateTwilioSignature(...): boolean {
const token = process.env.TWILIO_AUTH_TOKEN!;
return twilio.validateRequest(token, signature, url, params);
}
Terminal window
npm run build
chown -R yigit:yigit .next/ .env
pm2 restart ecutuningportal

Twilio webhook POST’unu simüle et. X-Twilio-Signature hesaplamak için:

Terminal window
# Node.js ile imza üret (local veya sunucuda)
node -e "
const twilio = require('twilio');
const token = 'YENI_TOKEN_BURAYA';
const url = 'https://ecutuningportal.com/api/twilio/webhook';
const params = {};
const sig = twilio.getExpectedTwilioSignature(token, url, params);
console.log(sig);
"

Üretilen imza ile POST at:

Terminal window
curl -s -o /dev/null -w "%{http_code}" \
-X POST https://ecutuningportal.com/api/twilio/webhook \
-H "X-Twilio-Signature: URETILEN_IMZA_BURAYA" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d ""
# Beklenen çıktı: 200
Terminal window
curl -s -o /dev/null -w "%{http_code}" \
-X POST https://ecutuningportal.com/api/twilio/webhook \
-H "X-Twilio-Signature: yanlis_imza_degeri" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d ""
# Beklenen çıktı: 403

Her iki test geçtiyse rotasyon tamamdır.


Kritik Uyarı: Twilio Console’da eski token’ı invalidate etmeden önce (Adım 5 öncesi) rollback yapılabilir. Adım 5 sonrasında Twilio eski token’ı tanımaz, .env’e geri yazsan da webhook’lar başarısız olur.

Terminal window
# .env'den TWILIO_AUTH_TOKEN_NEW satırını sil
# TWILIO_AUTH_TOKEN eski değerde kalsın
nano /var/www/vhosts/ecutuningportal.com/httpdocs/.env
# Dual-token kodu geri al (git revert veya manuel düzenleme)
git diff HEAD -- lib/twilio.ts # değişikliği gör
git checkout -- lib/twilio.ts # eski haline döndür
# Rebuild + restart
npm run build && chown -R yigit:yigit .next/ .env && pm2 restart ecutuningportal

Eski token Twilio’da geçersiz. Bu noktada rollback girişimi daha fazla hasara yol açar. Tek seçenek: Adım 3-7’yi yeni token üzerinden tamamlamak. Dual-token mode zaten çalışıyor olduğu için kalan adımlar hızlı ilerler.

Bu yüzden Adım 4’ü kesinleştirmeden Adım 5’e geçme.


Manuel rotation prosedürü insan hatasına açık. Orta vadede .env yerine bir secrets manager entegre edilmesi önerilir:

  • Doppler — Next.js + Laravel için native entegrasyon, rotation otomasyonu, audit log
  • AWS Secrets Manager — Lambda rotation function ile 90 günlük otomatik schedule, IAM tabanlı erişim
  • HashiCorp Vault — Self-hosted, dynamic secrets, lease-based token ömrü

Her üç seçenek de bu runbook’u devre dışı bırakır: token Twilio’da rotate edildiğinde uygulama sıfır manuel müdahaleyle yeni değeri okur. Geçiş önceliği: Doppler en düşük friction, AWS Secrets Manager production-grade.