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
- Une clé API ChinqIT, créée dans Clés API du tableau de bord ChinqIT.
- La CLI Supabase, connectée à votre projet.
Créer la fonction
supabase functions new chinqit-smsRemplacez 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_xxxVous 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-jwtActiver le hook
Dans Authentication → Sign In / Providers, activez Phone.
- Dans Supabase, ouvrez Authentication → Hooks → Send SMS hook et choisissez HTTPS.
- Saisissez l'URL
https://<project-ref>.supabase.co/functions/v1/chinqit-sms. - Générez le secret, puis enregistrez-le comme
SEND_SMS_HOOK_SECRETavecsupabase secrets setet 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.