Coduri de autentificare
Coduri de autentificare prin SMS fără Twilio: Supabase, Auth0, Clerk și Better Auth
Trimite codurile de autentificare din Supabase, Auth0, Clerk și Better Auth de pe telefonul tău Android, de pe numărul tău, fără cont la un API de SMS.
Scris de NARBOWEB SRL, firma care dezvoltă SMSTunnel Publicat 9 min de citit
Pornește videoclipul: Configurează SMSTunnel pe telefonul tău Android în 2 minute (1:34) Codurile de autentificare prin SMS sunt, de obicei, primul motiv pentru care un proiect își face cont la un API de SMS. Închiriezi un număr, îl înregistrezi acolo unde țara destinatarilor o cere și plătești pentru fiecare mesaj și pentru fiecare verificare. Dacă utilizatorii aplicației tale sunt mai ales în România, există o cale mai simplă: codurile pleacă de pe un telefon Android pe care îl ai deja, cu abonamentul pe care îl plătești deja.
Asta face SMSTunnel. Platforma ta de autentificare generează și verifică în continuare codurile, exact ca acum. Un pachet mic, @narcisbodea/smstunnel-otp, predă fiecare cod contului tău SMSTunnel, iar aplicația SMSTunnel de pe telefon îl trimite de pe SIM-ul tău. Utilizatorii primesc codul de la un număr pe care îl recunosc și la care pot răspunde.
Mai jos găsești cele patru platforme la care pachetul se leagă în câteva rânduri de cod (Supabase Auth, Auth0, Clerk și Better Auth), Ory, care nu are nevoie de cod deloc, autentificarea în WordPress și limitele pe care e bine să le știi înainte să treci pe telefonul tău.
Cum funcționează
- Un utilizator cere un cod: se conectează cu numărul de telefon, își adaugă unul sau confirmă autentificarea în doi pași.
- Platforma ta generează codul și apelează hook-ul, Action-ul, webhook-ul sau funcția ta, în locul furnizorului de SMS.
- Pachetul trimite mesajul la endpoint-ul SMSTunnel pentru coduri,
POST /api/v1/sms/send-2fa, cu cheia ta API. - Contul tău SMSTunnel îi predă mesajul telefonului, iar telefonul îl trimite de pe numărul tău.
- Utilizatorul tastează codul, iar platforma ta îl verifică, la fel ca până acum.
SMSTunnel nu verifică niciodată codurile. Spre deosebire de Twilio Verify, nu le generează și nu le validează: de asta se ocupă platforma ta, iar SMSTunnel doar livrează mesajul. Codurile au și o limită zilnică proprie, separată de celelalte mesaje, așa că o dimineață cu multe conectări nu consumă din notificările despre comenzi sau din mementouri.
Pachetul nu are dependențe la rulare (folosește doar Fetch și WebCrypto), deci merge în Node 18+, Deno (Supabase Edge Functions), Bun, Cloudflare Workers și Auth0 Actions.
Înainte să începi
- Instalează aplicația SMSTunnel din Google Play pe telefonul tău Android și autentifică-te. Intră în dashboard cu același cont: telefonul apare la Phones.
- În dashboard, deschide Apps → Add an app, alege Website or web app, dă-i un nume și apasă Create the key. Copiază cheia imediat, pentru că apare o singură dată. Păstreaz-o în secretele platformei, niciodată în cod care rulează în browser.
- Folosește coduri de 4 până la 10 cifre. Codurile implicite de 6 cifre ale platformelor de mai jos sunt în regulă; cele cu litere nu sunt acceptate.
Apoi instalează pachetul:
npm install @narcisbodea/smstunnel-otp
Supabase Auth: hook-ul Send SMS
În locul furnizorului de SMS integrat, Supabase poate apela un endpoint HTTPS cu numărul utilizatorului și codul. Pachetul îți dă acest endpoint, cu tot cu verificarea semnăturii Standard Webhooks. Creează supabase/functions/send-sms/index.ts:
import { createSupabaseSendSmsHook } from 'npm:@narcisbodea/smstunnel-otp@^1.0.0';
Deno.serve(
createSupabaseSendSmsHook({
apiKey: Deno.env.get('SMSTUNNEL_API_KEY')!,
hookSecret: Deno.env.get('SEND_SMS_HOOK_SECRETS')!, // v1,whsec_...
template: 'Codul tău Acme este {code}', // opțional
}),
);
Publică funcția fără verificarea JWT, pentru că o protejează semnătura:
supabase functions deploy send-sms --no-verify-jwt
În Supabase Dashboard, deschide Authentication → Hooks → Add a new hook → Send SMS hook, alege HTTPS, scrie https://<project-ref>.supabase.co/functions/v1/send-sms, apoi apasă Generate secret și Create. Salvează cele două secrete:
supabase secrets set SMSTUNNEL_API_KEY=... SEND_SMS_HOOK_SECRETS='v1,whsec_...'
La final, pornește furnizorul din Authentication → Sign In / Providers → Phone. Câmpurile pentru furnizorul de SMS nu se mai folosesc cât timp hook-ul e pornit. Lasă confirmarea automată a telefonului oprită, altfel înscrierile nu mai cer niciun cod.
Hook-ul trimite codul la numărul primit de la Supabase și adaugă semnul + pe care Supabase îl omite. Dacă SMSTunnel e ocupat sau nu poate fi contactat, răspunde cu 429 sau 503 și retry-after, iar Supabase reîncearcă în cele cinci secunde pe care le are la dispoziție. Pașii compleți, cu configurarea pentru dezvoltare locală, sunt pe pagina Supabase Auth.
Auth0: o Action de tip Custom Phone Provider
Auth0 își poate preda mesajele pentru telefon unei Action. Declanșatorul custom-phone-provider e cel recomandat de Auth0: un singur furnizor pentru MFA, conectare fără parolă prin SMS și înscriere cu numărul de telefon.
- Deschide Branding → Phone Provider → Custom și alege metoda de livrare Text.
- În editorul de Action, adaugă dependența
@narcisbodea/smstunnel-otpși secretulSMSTUNNEL_API_KEY, apoi lipește:
const { createAuth0CustomPhoneProvider } = require('@narcisbodea/smstunnel-otp');
const sendWithSmsTunnel = createAuth0CustomPhoneProvider();
exports.onExecuteCustomPhoneProvider = async (event, api) => {
await sendWithSmsTunnel(event, api);
};
- Salvează și folosește Send Test Message. Pentru MFA, pornește și Use Tenant-Level Messaging Provider din Security → Multi-factor Auth → Phone Message.
Codurile pleacă cu textul generat de Auth0, adică cu șablonul tău, în limba utilizatorului. Notificările fără cod, cum ar fi un cont blocat sau o parolă compromisă, pleacă drept mesaje obișnuite sau sunt ignorate dacă dai opțiunea { nonCodeMessages: 'skip' }. SMSTunnel trimite doar mesaje text, așa că o livrare prin apel vocal e refuzată, cu motivul explicat. Dacă îți trebuie doar MFA, merge și declanșatorul mai vechi Send Phone Message; ambele variante sunt pe pagina Auth0.
Clerk: webhook-ul sms.created
Când oprești Delivered by Clerk pentru un șablon de SMS, Clerk nu mai trimite el mesajul și îți trimite în schimb un webhook sms.created. În Next.js, ajunge fișierul app/api/webhooks/clerk-sms/route.ts:
import { createClerkSmsWebhook } from '@narcisbodea/smstunnel-otp';
export const POST = createClerkSmsWebhook({
apiKey: process.env.SMSTUNNEL_API_KEY!,
signingSecret: process.env.CLERK_SMS_WEBHOOK_SIGNING_SECRET!, // whsec_...
});
- În Clerk Dashboard, deschide Webhooks → Add Endpoint, scrie adresa ta, abonează-te la
sms.createdși copiază Signing Secret. - La Customization → SMS, deschide fiecare șablon pe care vrei să-l trimiți de pe telefon (Verification code, Reset password code…) și oprește Delivered by Clerk. Setarea se face separat pentru fiecare șablon.
- Lasă ruta publică în middleware-ul Clerk: webhook-urile nu au sesiune.
Handlerul verifică semnătura Svix și trimite textul generat de Clerk, după ce se asigură că acesta conține codul. Pentru Express și alte framework-uri, vezi pagina Clerk.
Better Auth: pluginul phoneNumber
Pluginul phoneNumber din Better Auth te întreabă cum să-și trimită codurile, iar smstunnelSendOTP() îi răspunde:
import { betterAuth } from 'better-auth';
import { phoneNumber } from 'better-auth/plugins';
import { smstunnelSendOTP } from '@narcisbodea/smstunnel-otp';
const apiKey = process.env.SMSTUNNEL_API_KEY!;
export const auth = betterAuth({
plugins: [
phoneNumber({
sendOTP: smstunnelSendOTP({ apiKey, template: 'Codul tău Acme este {code}' }),
sendPasswordResetOTP: smstunnelSendOTP({ apiKey, template: 'Codul Acme pentru resetarea parolei este {code}' }),
}),
],
});
Better Auth rulează sendOTP în fundal când poate, așa că autentificarea nu așteaptă trimiterea. Utilizatorii din România își scriu adesea numărul ca 0721 123 456, fără prefixul țării. Pentru ei, adaugă opțiunea defaultCountryCode: '40', sau verifică numerele cu phoneNumberValidator din plugin. Celelalte opțiuni sunt pe pagina Better Auth.
Ory, WordPress și orice altă platformă
Ory (Kratos găzduit la tine sau Ory Network) nu are nevoie de pachet: canalul HTTP al curierului său apelează direct SMSTunnel, cu câteva rânduri de configurare. Vezi pagina Ory.
Site-urile WordPress primesc coduri de autentificare din pluginul SMSTunnel: SMSTunnel → Settings → Two-Factor Authentication (2FA), apoi WordPress Login 2FA. Acoperă și autentificarea din „Contul meu” al magazinelor WooCommerce, pentru rolurile pe care le alegi, iar codurile sunt valabile implicit 5 minute.
Orice altă platformă poate folosi sendCode() din același pachet:
import { sendCode, SmsTunnelOtpError } from '@narcisbodea/smstunnel-otp';
await sendCode({
apiKey: process.env.SMSTUNNEL_API_KEY!,
to: '+40712345678',
code: '123456',
template: 'Codul tău Acme este {code}', // sau message: 'textul întreg'; codul e adăugat dacă lipsește
// deviceId, defaultCountryCode, serverUrl, timeoutMs (implicit 10000)
});
Când ceva nu merge, aruncă o eroare SmsTunnelOtpError, cu status (codul HTTP), un code precum RATE_LIMITED și retryable: true pentru erorile la care merită să reîncerci.
Ce înseamnă „cod” pentru SMSTunnel
Endpoint-ul pentru coduri refuză mesajele fără cod:
- Un cod are între 4 și 10 cifre de sine stătătoare (
482913,Cod: 1234,G-123456) sau două grupuri de câte 3 cifre legate prin cratimă (123-456). - Nu sunt coduri: combinațiile cu litere, numerele de 11 cifre sau mai lungi, cifrele scrise imediat după
+(un număr de telefon) și cifrele lipite de altele prin.,,,:sau/, cum ar fi prețurile, orele și datele. - Un mesaj poate avea cel mult 320 de caractere. Pachetul refuză unul mai lung înainte să apeleze SMSTunnel.
Un mesaj fără cod e refuzat cu eroarea 400. Mesajele care nu conțin coduri pleacă prin endpoint-ul obișnuit de trimitere.
Limite și când se potrivește mai bine un API de SMS
Înainte să treci pe telefonul tău, e bine să știi câteva lucruri:
- Un singur număr pe mesaj. Fiecare cod merge la o singură persoană.
- 30 de trimiteri pe minut. Peste această limită, SMSTunnel răspunde cu 429, iar pachetul marchează eroarea ca una la care se poate reîncerca.
- Telefonul trebuie să fie pornit și conectat la internet. Dacă e offline, codul așteaptă și pleacă imediat ce telefonul revine. Un cod care așteaptă prea mult poate expira până ajunge, așa că ține telefonul încărcat și conectat.
- Limita zilnică. Planul Gratuit include 50 de coduri de autentificare pe zi. Începând cu planul Starter, de 9 $ pe lună, codurile de autentificare nu mai au limită zilnică. Prețurile sunt în dolari, fără taxe, iar clienții din România primesc factura fiscală în lei, la cursul BNR, prin e-Factura.
- Se aplică condițiile operatorului tău, pentru că mesajele pleacă prin abonamentul tău de telefonie mobilă.
Ca reper, paginile Twilio indicau, când le-am verificat în noiembrie 2026, 0,05 $ pentru fiecare verificare reușită prin Twilio Verify, plus 0,0083 $ pentru fiecare SMS în SUA, iar prețurile diferă de la o țară la alta. Twilio sau un alt furnizor de API pentru SMS rămâne alegerea mai bună dacă trimiți volume mari, ai nevoie de numere scurte (short codes), de un nume de expeditor în locul numărului, de numere 10DLC în SUA sau de multe țări. Le poți folosi și pe amândouă: vezi SMSTunnel comparat cu Twilio și cât costă SMS-urile trimise de pe SIM-ul tău.
Întrebări frecvente
Trebuie să schimb felul în care platforma generează sau verifică codurile?
Nu. Supabase, Auth0, Clerk, Better Auth și Ory generează, păstrează și verifică în continuare codurile. Se schimbă doar livrarea.
Pot scrie eu textul mesajului?
Da. Dă o opțiune template cu {code} în locul în care vrei codul, de exemplu „Codul tău Acme este {code}”. Fără ea, Auth0 și Clerk trimit textul generat din propriile șabloane.
Pot trimite coduri de pe mai multe telefoane?
Poate trimite oricare dintre telefoanele legate de contul tău. sendCode() și smstunnelSendOTP() primesc un deviceId ca să alegi unul, iar Action-ul din Auth0 îl citește din secretul SMSTUNNEL_DEVICE_ID. Fără el, trimite telefonul tău implicit.
Rămâne codul scris undeva în jurnale?
Pachetul nu scrie în jurnale nici codurile, nici cheile. Fiecare handler de webhook ține minte și ID-urile webhook-urilor recente (în instanța care rulează), așa că un webhook reîncercat nu trimite același cod de două ori.
Vezi și
Alte articole
Încearcă-l cu telefonul tău
Instalează aplicația Android, autentifică-te, iar software-ul tău poate trimite primul mesaj în câteva minute. Planul Gratuit nu cere card bancar.