ChinqIT VerifyChinqIT Verify

Supabase : connexion par téléphone avec ChinqIT

Envoyez les codes de connexion Supabase par SMS avec ChinqIT.

Envoyez les codes de connexion de Supabase Auth par SMS avec ChinqIT, grâce à une petite fonction.

Avant de commencer

Créer la fonction

supabase functions new chinqit-sms

Remplacez le contenu de supabase/functions/chinqit-sms/index.ts par ce code :

// Supabase "Send SMS" hook: checks the Supabase signature, then sends the
// login code as an SMS through ChinqIT.
// Env vars: CHINQIT_API_KEY, SEND_SMS_HOOK_SECRET, CHINQIT_SMS_LANGUAGE (fr, en or ar; default fr).
import { Webhook } from "npm:standardwebhooks@1.0.0";

const TEXTS: Record<string, (otp: string) => string> = {
  fr: (otp) => `Votre code ChinqIT est ${otp}`,
  en: (otp) => `Your ChinqIT code is ${otp}`,
  ar: (otp) => `رمز ChinqIT الخاص بك هو ${otp}`,
};

// Supabase only reads the error message when the hook answers 200, so refusals
// go out as 200 with the real code inside. 429 and 503 stay real statuses so
// Supabase retries.
const reply = (status: number, message?: string) => {
  if (message) console.error(message);
  const retry = status === 429 || status === 503;
  return new Response(JSON.stringify(message ? { error: { http_code: status, message } } : {}), {
    status: message && !retry ? 200 : status,
    headers: { "Content-Type": "application/json", ...(retry && { "retry-after": "true" }) },
  });
};

export async function handler(req: Request): Promise<Response> {
  const secret = Deno.env.get("SEND_SMS_HOOK_SECRET")!.replace(/^v1,/, "").replace(/^whsec_/, "");
  const payload = await req.text();
  let data: { user: { phone: string }; sms: { otp: string } };
  try {
    data = new Webhook(secret).verify(payload, Object.fromEntries(req.headers)) as typeof data;
  } catch {
    return reply(401, "Invalid signature");
  }

  const phone = data.user.phone.startsWith("+") ? data.user.phone : `+${data.user.phone}`;
  const text = TEXTS[Deno.env.get("CHINQIT_SMS_LANGUAGE") ?? "fr"] ?? TEXTS.fr;
  try {
    const res = await fetch("https://sms.chinqit.com/api/v2/notify", {
      method: "POST",
      headers: { "x-api-key": Deno.env.get("CHINQIT_API_KEY")!, "Content-Type": "application/json" },
      body: JSON.stringify({ phoneNumber: phone, message: text(data.sms.otp) }),
      signal: AbortSignal.timeout(4000),
    });
    if (res.ok) return reply(200);
    const err = await res.json().catch(() => ({}));
    const code = err.code ?? err.errorCode;
    const message = err.message ?? "ChinqIT refused the message";
    return reply(res.status, code ? `${code}: ${message}` : message);
  } catch {
    return reply(503, "Could not reach ChinqIT, try again");
  }
}

Deno.serve(handler);

Secrets

supabase secrets set CHINQIT_API_KEY=votre_cle_api SEND_SMS_HOOK_SECRET=v1,whsec_xxx

Vous obtiendrez SEND_SMS_HOOK_SECRET à l'étape « Activer le hook ». Pour changer la langue du SMS, ajoutez CHINQIT_SMS_LANGUAGE=fr, en ou ar (fr par défaut).

Déployer

supabase functions deploy chinqit-sms --no-verify-jwt

Activer le hook

Dans Authentication → Sign In / Providers, activez Phone.

  1. Dans Supabase, ouvrez Authentication → Hooks → Send SMS hook et choisissez HTTPS.
  2. Saisissez l'URL https://<project-ref>.supabase.co/functions/v1/chinqit-sms.
  3. Générez le secret, puis enregistrez-le comme SEND_SMS_HOOK_SECRET avec supabase secrets set et redéployez la fonction.

Limite d'envoi

Dans Authentication → Rate Limits, Supabase limite par défaut à 30 SMS par heure. Augmentez-la pour correspondre au nombre de connexions attendues.

Tester

await supabase.auth.signInWithOtp({ phone: '+22238089336' })

// Après réception du SMS
await supabase.auth.verifyOtp({ phone: '+22238089336', token: '123456', type: 'sms' })

Si ça ne marche pas

L'erreur apparaît dans la réponse de signInWithOtp et dans les logs de la fonction (Edge Functions → chinqit-sms → Logs), sous la forme CODE: message. Consultez ensuite le Dépannage.

On this page