Open-source · Auto-hébergé · Microservices

Des codes OTP livrés
par messagerie,
sans API payante.

Une API d'authentification réutilisable qui génère, envoie et vérifie des codes à usage unique via Telegram, Signal ou WhatsApp — déployée en une commande sur votre propre serveur.

6
chiffres CSPRNG
5 min
durée de validité
3
canaux + repli
0
code stocké en clair
O
PhoneVerify Bot
en ligne
Votre code de vérification :· · · · · ·valide 5 minutes
· · · · · ·
Vérifié — code à usage unique
FastAPIRedisDocker ComposeTelegram Bot APIsignal-cliBaileysHMAC-SHA256pytestmicroservices FastAPIRedisDocker ComposeTelegram Bot APIsignal-cliBaileysHMAC-SHA256pytestmicroservices

Un moteur OTP sérieux,
pas un gadget.

Tout ce qu'il faut pour délivrer et vérifier des codes en production — sans dépendre d'un fournisseur payant.

Cryptographiquement sûr

Codes générés par CSPRNG, stockés sous forme de digest HMAC-SHA256 salé — jamais en clair, comparaison en temps constant.

Multi-canal avec repli

Telegram, Signal, WhatsApp derrière une interface commune. Si un canal échoue, le suivant prend le relais automatiquement.

Expiration & verrouillage

TTL court configurable, usage unique, compteur de tentatives et verrouillage après dépassement — le tout dans Redis.

Anti-abus intégré

Limitation de débit par numéro (fenêtre glissante) et par IP, cooldown de renvoi — vos numéros expéditeurs et vos utilisateurs sont protégés.

100 % auto-hébergé

Vos données restent chez vous : un seul docker compose up, configuration entièrement par variables d'environnement.

API réutilisable

Trois endpoints REST, clés API par application, réponses JSON normalisées — intégrable en dix lignes dans n'importe quel backend.

Trois messageries, une interface.

Production · Officiel

Telegram

API Bot officielle — gratuite, contractuellement licite. Le canal recommandé.

  • Gratuit dans les limites d'usage Telegram
  • Liaison par partage de contact (polling ou webhook)
  • Aucun numéro expéditeur à risque
Expérimental

Signal

Sidecar signal-cli REST — client non officiel, réservé aux usages propres.

  • Numéro expéditeur dédié requis
  • Profil Docker optionnel
  • Sensible aux changements côté serveur
Expérimental

WhatsApp

Bridge Baileys simulant un appareil lié — contraire aux conditions WhatsApp.

  • Liaison par QR code, session persistée
  • Risque de bannissement du numéro
  • À réserver aux tests, quotas bas
Connecteurs non officiels. Signal et WhatsApp reposent sur des clients non documentés : risque de bannissement du numéro expéditeur et de rupture de compatibilité. En production, privilégiez Telegram ou ajoutez un adaptateur vers un fournisseur officiel — l'interface commune le permet sans toucher au reste. Détails : docs/RISKS.md.

De la requête à la vérification.

1

Requête

Votre app appelle /v1/otp/request avec le numéro E.164 et les canaux souhaités.

2

Envoi

Code CSPRNG généré, tenté sur le canal préféré puis les replis. Seul le digest HMAC est persisté.

3

Saisie

L'utilisateur reçoit le code dans sa messagerie et le soumet à votre application.

4

Vérification

/v1/otp/verify compare en temps constant — usage unique, expiration et verrouillage gérés.

# Demande d'OTP
curl -X POST https://otp.mondomaine.fr/v1/otp/request \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"phone":"+33612345678","channel":"telegram","fallback_channels":["signal"]}'

# → {"request_id":"9f2c…","status":"sent","channel_used":"telegram","expires_in":300}

curl -X POST https://otp.mondomaine.fr/v1/otp/verify \
  -H "X-API-Key: $API_KEY" -H "Content-Type: application/json" \
  -d '{"request_id":"9f2c…","code":"483920"}'

# → {"status":"verified"}
import httpx

API = "https://otp.mondomaine.fr"
H = {"X-API-Key": API_KEY}

r = httpx.post(f"{API}/v1/otp/request", headers=H, json={
    "phone": "+33612345678",
    "channel": "telegram",
    "fallback_channels": ["signal"],
})
rid = r.json()["request_id"]

code = input("Code reçu : ")
ok = httpx.post(f"{API}/v1/otp/verify", headers=H,
                json={"request_id": rid, "code": code})
assert ok.json()["status"] == "verified"
const API = "https://otp.mondomaine.fr";
const H = { "X-API-Key": API_KEY, "Content-Type": "application/json" };

const req = await fetch(`${API}/v1/otp/request`, {
  method: "POST", headers: H,
  body: JSON.stringify({
    phone: "+33612345678",
    channel: "telegram",
    fallback_channels: ["signal"],
  }),
});
const { request_id } = await req.json();

const res = await fetch(`${API}/v1/otp/verify`, {
  method: "POST", headers: H,
  body: JSON.stringify({ request_id, code: userCode }),
});
// res.json().status === "verified"

Conçue pour résister.

Chaque couche applique le principe du moindre exposé — même une fuite de la base ne révèle ni codes ni numéros.

CSPRNGGénération via secrets — imprévisible et uniforme.
Hachage salé + poivreHMAC-SHA256 avec sel aléatoire par code et poivre global d'environnement.
Temps constantcompare_digest — aucune fuite par timing sur la comparaison.
Usage unique + TTLSuppression au premier succès, expiration native Redis.
Verrouillage anti-bruteforceN tentatives max puis verrou — même le bon code est refusé.
Logs sans secretAucun code ni numéro en clair journalisé — empreintes HMAC tronquées.
Auth à deux étagesClé API clientes + jeton interne entre services, comparaison anti-timing.
Rate-limit multi-couchesPar numéro, par IP, cooldown de renvoi — anti-spam et protection des expéditeurs.

Simple et transparent.

Auto-hébergé : vous payez votre serveur, pas vos messages.

Gratuit

0 € /mois

Pour démarrer et tester la plateforme.

  • 1 application, 2 clés API
  • 1 canal actif (Telegram)
  • 500 codes OTP / mois
  • Quotas anti-abus intégrés
  • Documentation complète
Créer un compte

Entreprise

Sur mesure

Pour les flottes et la conformité.

  • Déploiement dédié / on-premise
  • SLA et audit de sécurité
  • Adaptateurs sur mesure (SMS, email)
  • SSO / SAML
  • Accompagnement RGPD
Nous contacter

Déployez votre passerelle OTP.

Clonez, configurez vos secrets, lancez Compose. C'est tout.

$ cp .env.example .env
$ openssl rand -hex 32   # OTP_PEPPER, INTERNAL_TOKEN…
$ docker compose up -d --build
$ curl http://localhost:8080/health
# {"status":"ok"}