Autenticación de Node.js con Twilio Verify

 

 

 

  • ¡Registro!
  • Patrones de diseño para interfaces de IA, con Vitaly Friedman

  • Índice
    1. ¿Qué hay de malo con las contraseñas?
    2. Ingrese OTP
  • Tabla de contenido
  • Requisitos
  • Descripción básica de la autenticación en aplicaciones web
    1. ¿Qué es la autenticación?
    2. ¿Qué es la autorización?
  • Configurando nuestra aplicación
  • Construyendo un servidor Express
    1. ¿Por qué necesitamos Express?
  • Integrando MongoDB en nuestra aplicación Express
    1. Cifrar contraseñas
  • Construyendo las vistas de nuestra aplicación utilizando el motor de plantillas EJS
    1. Arquitectura frontal
    2. Construyendo los parciales
    3. Creación de la página del panel
    4. Construyendo la página de error
    5. Construyendo la página de inicio
    6. Construyendo la página de inicio de sesión
    7. Construyendo la página de verificación
    8. Creación de la página de registro
  • En este tutorial, aprenderá cómo integrar la autenticación de dos factores en su aplicación Express.js. Creará una aplicación rápida que autentica a los usuarios mediante la autenticación tradicional basada en contraseña con una capa adicional de seguridad utilizando OTP impulsadas por el servicio Twilio Verify. Aprenderá cómo crear un backend rápido desde cero e implementar la autenticación mientras aprende sobre la arquitectura MVC. MongoDB es la base de datos elegida y la interfaz de usuario se crea utilizando EJS. Al final de este tutorial, tendrá una aplicación rápida completamente funcional que implementa OTP y contraseñas para la autenticación de usuarios.

     

    Integrar la autenticación en una aplicación es una tarea tediosa. Sin embargo, asegurarse de que esta autenticación sea a prueba de balas es aún más difícil. Como desarrolladores, está fuera de nuestro control lo que los usuarios hacen con sus contraseñas, cómo las protegen, a quién se las entregan o cómo las generan. Todo lo que podemos hacer es acercarnos lo suficiente para asegurarnos de que la solicitud de autenticación fue realizada por nuestro usuario y no por otra persona. Las OTP ciertamente ayudan con eso, y servicios como Twilio Verify nos ayudan a generar OTP seguras rápidamente sin tener que preocuparnos por la lógica.

    ¿Qué hay de malo con las contraseñas?

    Los desarrolladores enfrentan varios problemas cuando utilizan únicamente la autenticación basada en contraseña, ya que presenta los siguientes problemas:

    1. Los usuarios pueden olvidar sus contraseñas y escribirlas (lo que las hace robables);
    2. Los usuarios pueden reutilizar contraseñas en todos los servicios (haciendo que todas sus cuentas sean vulnerables a una violación de datos);
    3. Los usuarios pueden utilizar contraseñas sencillas con fines de recuerdo, lo que las hace relativamente fáciles de piratear.

    Ingrese OTP

    Una contraseña de un solo uso ( OTP ) es una contraseña o PIN válido solo para una sesión o transacción de inicio de sesión. Dado que solo se puede usar una vez, estoy seguro de que ya puedes ver cómo el uso de OTP compensa las deficiencias de las contraseñas tradicionales.

    Las OTP añaden una capa adicional de seguridad a las aplicaciones, que el sistema tradicional de autenticación de contraseñas no puede proporcionar. Las OTP se generan aleatoriamente y solo son válidas por un corto período de tiempo, lo que evita varias deficiencias asociadas con la autenticación tradicional basada en contraseña.

    Las OTP se pueden utilizar para sustituir las contraseñas tradicionales o reforzar las contraseñas utilizando el enfoque de autenticación de dos factores (2FA). Básicamente, las OTP se pueden utilizar siempre que sea necesario garantizar la identidad de un usuario confiando en un medio de comunicación personal propiedad del usuario, como el teléfono, el correo, etc.

    Este artículo está dirigido a desarrolladores que quieran obtener información sobre:

    1. Aprenda a crear una aplicación express.js de pila completa;
    2. Implementar autenticación con passport.js;
    3. Cómo Twilio Verify para la verificación de usuarios por teléfono.

    Para lograr estos objetivos, crearemos una aplicación de pila completa utilizando node.js , express.js , EJS con autenticación realizada mediante pasaporte.js y rutas protegidas que requieren OTP para acceder.

     

    Nota : Me gustaría mencionar que usaremos algunos paquetes de terceros (creados por otras personas) en nuestra aplicación. Esta es una práctica común, ya que no es necesario reinventar la rueda. ¿Podríamos crear nuestro propio servidor de nodos? Sí, claro. Sin embargo, ese tiempo podría dedicarse mejor a crear una lógica específica para nuestra aplicación.

    Tabla de contenido

    1. Descripción básica de la autenticación en aplicaciones web;
    2. Construyendo un servidor Express;
    3. Integrar MongoDB en nuestra aplicación Express;
    4. Construyendo las vistas de nuestra aplicación usando el motor de plantillas EJS;
    5. Autenticación básica mediante un número de pasaporte;
    6. Usando Twilio Verify para proteger rutas.

    Requisitos

    • Nodo.js
    • MongoDB
    • Un editor de texto (por ejemplo, VS Code)
    • Un navegador web (por ejemplo, Chrome, Firefox)
    • Comprensión de HTML, CSS, JavaScript, Express.js

    Aunque crearemos toda la aplicación desde cero, aquí está el repositorio de GitHub para el proyecto.

    Descripción básica de la autenticación en aplicaciones web

    ¿Qué es la autenticación?

    La autenticación es todo el proceso de identificar a un usuario y verificar que tiene una cuenta en nuestra aplicación.

    No debe confundirse la autenticación con la autorización. Aunque trabajan de la mano, no hay autorización sin autenticación.

    Dicho esto, veamos de qué se trata la autorización.

    ¿Qué es la autorización?

    La autorización, en su forma más básica, tiene que ver con los permisos del usuario: lo que un usuario puede hacer en la aplicación. En otras palabras:

    1. Autenticación: ¿Quién eres?
    2. Autorización: ¿Qué puedes hacer?

    La autenticación viene antes que la autorización.
    No hay Autorización sin Autenticación.

    La forma más común de autenticar a un usuario es mediante usernamey password.

    Configurando nuestra aplicación

    Para configurar nuestra aplicación, creamos nuestro directorio de proyecto:

    mkdir authWithTwilioVerify

    Construyendo un servidor Express

    Usaremos Express.js para construir nuestro servidor.

    ¿Por qué necesitamos Express?

    Construir un servidor Nodepuede resultar tedioso, pero los marcos nos facilitan las cosas. es el marco web Expressmás popular . NodeNos permite:

    • Escribir controladores para solicitudes con diferentes HTTPverbos en diferentes URLrutas (rutas);
    • Integre con viewmotores de renderizado para generar respuestas insertando datos en plantillas;
    • Establezca configuraciones comunes de aplicaciones web, como las portutilizadas para conectarse y la ubicación de las plantillas utilizadas para representar la respuesta;
    • Agregue procesamiento de solicitudes adicional middlewareen cualquier punto dentro del proceso de manejo de solicitudes.

    Además de todo esto, los desarrolladores han creado paquetes de middleware compatibles para abordar casi cualquier problema de desarrollo web.

     

    En nuestro authWithTwilioVerifydirectorio, inicializamos un archivo package.jsonque contiene información sobre nuestro proyecto.

    cd authWithTwilioVerifynpm init -y

    De acuerdo con la arquitectura Model View Controller (MVC), tenemos que crear las siguientes carpetas en nuestro authWithTwilioVerifydirectorio:

    mkdir public controllers views routes config models

    Muchos desarrolladores tienen diferentes razones para usar la arquitectura MVC, pero para mí personalmente es porque:

    1. Fomenta la separación de preocupaciones;
    2. Ayuda a escribir código limpio;
    3. Proporciona una estructura a mi código base y, dado que otros desarrolladores lo usan, comprender el código base no será un problema.
    • Controllersel directorio alberga los controladores;
    • Modelsel directorio contiene nuestros modelos de bases de datos;
    • Publicel directorio contiene nuestros activos estáticos, por ejemplo, archivos CSS, imágenes, etc.;
    • Viewsel directorio contiene las páginas que se mostrarán en el navegador;
    • Routesdirectorio contiene las diferentes rutas de nuestra aplicación;
    • ConfigEl directorio contiene información que es peculiar de nuestra aplicación.

    Necesitamos instalar los siguientes paquetes para construir nuestra aplicación:

    • nodemonreinicia automáticamente nuestro servidor cuando realizamos cambios;
    • expressnos brinda una interfaz agradable para manejar rutas;
    • express-sessionnos permite manejar sesiones fácilmente en nuestra aplicación express;
    • connect-flashnos permite mostrar mensajes a nuestros usuarios.
    npm install nodemon -D

    Agregue el siguiente script en el package.jsonarchivo para iniciar nuestro servidor usando nodemon.

    "scripts": { "dev": "nodemon index" },
    npm install express express-session connect-flash --save

    Crea un index.jsarchivo y agrega los paquetes necesarios para nuestra aplicación.

    Tenemos requirelos paquetes instalados en nuestro index.jsarchivo para que nuestra aplicación se ejecute bien y luego configuramos los paquetes de la siguiente manera:

    const path = require('path')const express = require('express');const session = require('express-session')const flash = require('connect-flash')const port = process.env.PORT || 3000const app = express();app.use('/static', express.static(path.join(__dirname, 'public')))app.use(session({ secret: "please log me in", resave: true, saveUninitialized: true }));app.use(express.json())app.use(express.urlencoded({ extended: true }))// Connect flashapp.use(flash());// Global variablesapp.use(function(req, res, next) { res.locals.success_msg = req.flash('success_msg'); res.locals.error_msg = req.flash('error_msg'); res.locals.error = req.flash('error'); res.locals.user = req.user next();});//define error handlerapp.use(function(err, req, res, next) { res.render('error', { error : err })})//listen on portapp.listen(port, () = { console.log(`app is running on port ${port}`)});

    Analicemos el segmento de código anterior.

     

    Además de las requiredeclaraciones, utilizamos la app.use()función, que nos permite utilizar el nivel de aplicación middleware.

    Las funciones de middleware son funciones que tienen acceso al objeto de solicitud, al objeto de respuesta y a la siguiente función de middleware en el ciclo de solicitud y respuesta de la aplicación.

    La mayoría de los paquetes que tienen acceso al estado de nuestra aplicación (objetos de solicitud y respuesta) y pueden alterar esos estados se suelen utilizar como middleware. Básicamente, el middleware agrega funcionalidad a nuestra aplicación express.

    Es como entregar el estado de la aplicación a la función del middleware, diciendo aquí está el estado, haz lo que quieras con él y llama la next()función al siguiente middleware.

    Finalmente, le decimos a nuestro servidor de aplicaciones que escuche las solicitudes en el puerto 3000.

    Luego en la terminal ejecuta:

    npm run dev

    Si lo ve app is running on port 3000en la terminal, significa que nuestra aplicación se está ejecutando correctamente.

    Integrando MongoDB en nuestra aplicación Express

    MongoDB almacena datos como documentos. Estos documentos se almacenan en MongoDB en formato JSON (JavaScript Object Notation). Como usamos Node.js, es bastante fácil convertir datos almacenados en MongoDB en objetos JavaScript y manipularlos.

    Para instalar MongoDB en su máquina, visite la documentación de MongoDB .

    Para integrar MongoDB en nuestra aplicación express, usaremos Mongoose . Mongoose es un ODM (que es el acrónimo de object data mapper).

    Básicamente, Mongoose nos facilita el uso de MongoDB en nuestra aplicación al crear un contenedor alrededor de las funciones nativas de MongoDB.

    npm install mongoose --save

    En index.js, se requiere mongoose:

    const mongoose = require('mongoose')const app = express()//connect to mongodbmongoose.connect('mongodb://localhost:27017/authWithTwilio', { useNewUrlParser: true, useUnifiedTopology: true }).then(() = { console.log(`connected to mongodb`)}).catch(e = console.log(e))

    La mongoose.connect()función nos permite configurar una conexión a nuestra base de datos MongoDB utilizando la cadena de conexión.

    El formato de la cadena de conexión es mongodb://localhost:27017/{database_name}.

    mongodb://localhost:27017/es el host predeterminado de MongoDB y database_namees como queramos llamar a nuestra base de datos.

    Mongoose se conecta a la base de datos llamada database_name. Si no existe, crea una base de datos database_namey se conecta a ella.

     

    Mongoose.connect()es una promesa, por lo que siempre es una buena práctica registrar un mensaje en la consola en los métodos then()y catch()para informarnos si la conexión fue exitosa o no.

    Creamos nuestro modelo de usuario en nuestro modelsdirectorio:

    cd modelstouch user.js

    user.jsrequiere mangosta y crea nuestro esquema de usuario: Notarias latinas cerca de mi

    const mongoose = require('mongoose');const userSchema = new mongoose.Schema({ name : { type: String, required: true }, username : { type: String, required: true }, password : { type: String, required: true }, phonenumber : { type: String, required: true }, email : { type: String, required: true }, verified: Boolean})module.exports = mongoose.model('user', userSchema)

    A schemaproporciona una estructura para nuestros datos. Muestra cómo se deben estructurar los datos en la base de datos. Siguiendo el segmento de código anterior, especificamos que un objeto de usuario en la base de datos siempre debe tener name, username, password, phonenumbery email. Dado que esos campos son obligatorios, si los datos ingresados ​​en la base de datos carecen de alguno de estos campos obligatorios, mongoose arroja un error.

    Aunque puedes crear datos sin esquema en MongoDB, no es recomendable hacerlo; créeme, tus datos serían un desastre. Además, los esquemas son geniales. Le permiten dictar la estructura y la forma de los objetos en su base de datos. ¿Quién no querría esos poderes?

    Cifrar contraseñas

    Advertencia: nunca almacene las contraseñas de los usuarios como texto sin formato en su base de datos.
    Cifre siempre las contraseñas antes de enviarlas a la base de datos.

    La razón por la que necesitamos cifrar las contraseñas de los usuarios es la siguiente: en caso de que alguien de alguna manera obtenga acceso a nuestra base de datos, tenemos cierta seguridad de que las contraseñas de los usuarios son seguras, porque lo único que esta persona vería sería un archivo hash. Esto proporciona cierto nivel de garantía de seguridad, pero un pirata informático sofisticado aún puede descifrarlo hashsi tiene las herramientas adecuadas. De ahí la necesidad de OTP, pero centrémonos en cifrar las contraseñas de los usuarios por ahora.

    bcryptjsproporciona una forma de cifrar y descifrar las contraseñas de los usuarios.

    npm install bcryptjs

    En models/user.js, se requiere bcryptjs:

    //after requiring mongooseconst bcrypt = require('bcryptjs')//before module.exports//hash password on saveuserSchema.pre('save', async function() { return new Promise( async (resolve, reject) = { await bcrypt.genSalt(10, async (err, salt) = { await bcrypt.hash(this.password, salt, async (err, hash) = { if(err) { reject (err) } else { resolve (this.password = hash) } }); }); })})userSchema.methods.validPassword = async function(password) { return new Promise((resolve, reject) = { bcrypt.compare(password, this.password, (err, res) = { if(err) { reject (err) } resolve (res) }); })}

    El código anterior hace un par de cosas. Veámoslos.

     

    Es userSchema.pre('save', callback)una mongoose hookque nos permite manipular datos antes de guardarlos en la base de datos. En el callback function, devolvemos una promesa que intenta obtener hash(encrypt) bcrypt.hash()la contraseña utilizando la que bcrypt.genSalt()generamos. Si se produce un error durante esto hashing, nosotros rejecto nosotros resolveconfigurando this.password = hash. this.passwordsiendo el userSchema password.

    A continuación, mongoosenos proporciona una manera de agregar métodos a esquemas usando el archivo schema.methods.method_name. En nuestro caso, estamos creando un método que nos permite validar las contraseñas de los usuarios. Al asignar un valor de función a *userSchema.methods.validPassword*, podemos usar fácilmente el método de comparación bcryptjs bcryprt.compare()para verificar si la contraseña es correcta o no.

    bcrypt.compare()toma dos argumentos y una devolución de llamada. La passwordes la contraseña que se pasa al llamar a la función, mientras que this.passwordes la de userSchema.

    Prefiero este método de validar la contraseña de los usuarios porque es como una propiedad del objeto de usuario. Uno podría llamar fácilmente User.validPassword(password)y obtener respuesta verdadera o falsa.

    Con suerte, podrás ver la utilidad de la mangosta. Además de crear un esquema que da estructura a los objetos de nuestra base de datos, también proporciona buenos métodos para manipular esos objetos; eso habría sido de otra manera si se hubiera usado solo MongoDB nativo.

    Express es para Node, como Mongoose es para MongoDB.

    Construyendo las vistas de nuestra aplicación utilizando el motor de plantillas EJS

    Antes de comenzar a crear las vistas de nuestra aplicación, echemos un vistazo a la arquitectura front-end de nuestra aplicación.

    Arquitectura frontal

    EJSes un motor de plantillas que funciona directamente con Express. No es necesario un marco de interfaz de usuario diferente. EJShace que la transferencia de datos sea muy fácil. También hace que sea más fácil realizar un seguimiento de lo que sucede, ya que no es necesario cambiar del back-end al front-end.

    Tendremos un viewsdirectorio que contendrá los archivos que se mostrarán en el navegador. Todo lo que tenemos que hacer es llamar al res.render()método desde nuestro controlador. Por ejemplo, si deseamos representar la página de inicio de sesión, es tan simple como res.render('login'). También podríamos pasar datos a las vistas agregando un argumento adicional, que es un objeto del render()método, como res.render('dashboard', { user }). Luego, en nuestro view, podríamos mostrar los datos con el evaluation syntax %= %. Todo lo que tiene esta etiqueta se evalúa; por ejemplo, %= user.username %muestra el valor de la propiedad de nombre de usuario del objeto de usuario. Además de la sintaxis de evaluación, EJStambién proporciona una sintaxis de control ( % %), que nos permite escribir declaraciones de control del programa como condicionales, bucles, etc.

     

    Básicamente, EJSnos permite incrustar JavaScript en nuestro HTML.

    npm install ejs express-ejs-layouts --save

    En index.js, se requiere express-ejs-layouts:

    //after requiring connect-flashconst expressLayouts = require('express-ejs-layouts')//after the mongoose.connect logicapp.use(expressLayouts);app.set('view engine', 'ejs');

    Entonces:

    cd viewstouch layout.ejs

    En views/layout.ejs,

    !DOCTYPE htmlhtml head meta charset="UTF-8" / meta name="viewport" content="width=device-width, initial-scale=1.0" / meta http-equiv="X-UA-Compatible" content="ie=edge" / link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous" link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.css" link rel="stylesheet" href="/static/css/app.css" link rel="stylesheet" href="/static/css/intlTelInput.css" titleNode js authentication/title /head body div %- body % /div script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous" /script script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.js"/script /body/html

    El layout.ejsarchivo sirve como un index.htmlarchivo, donde podemos incluir todos nuestros scripts y hojas de estilo. Luego, en divwith clases ui container, representamos bodyel resto de las vistas de nuestra aplicación.

    Usaremos la interfaz de usuario semántica como nuestro marco CSS.

    Construyendo los parciales

    Los parciales son donde almacenamos código reutilizable, para no tener que reescribirlos cada vez. Lo único que hacemos es incluirlos allí donde sean necesarios.

    Se podría pensar en los parciales como componentes en los marcos de front-end: fomentan el código DRY y también la reutilización del código. Piense en los parciales como una versión anterior de los componentes.

    Por ejemplo, queremos parciales para nuestro menú, de modo que no tengamos que escribir código cada vez que necesitemos el menú en nuestra página.

     

    cd viewsmkdir partials

    Crearemos dos archivos en la /views/partialscarpeta:

    cd partialstouch menu.ejs message.ejs

    En menu.ejs,

    div a href="/" Home /a % if(locals.user) { % a href="/users/dashboard" dashboard /a div a class='ui item' %= user.username % /a a href="/users/logout" Logout /a /div % } else {% div a href="/users/signup" Sign Up /a a href="/users/login" Login /a /div % } % /div

    En message.ejs,

    % if(typeof errors != 'undefined'){ % % errors.forEach(function(error) { % div i/i div User registration unsuccessful /div %= error.msg % /div% }); % % } % % if(success_msg != ''){ %div i/i div Your user registration was successful. /div %= success_msg %/div% } % % if(error_msg != ''){ %div i/i div /div %= error_msg %/div% } % % if(error != ''){ %div i/i div /div %= error %/div% } %

    Creación de la página del panel

    En nuestra carpeta de vistas, creamos un dashboard.ejsarchivo:

    %- include('./partials/menu') %h1 DashBoard/h1

    Aquí incluimos el menu partialspara que tengamos el menú en la página.

    Construyendo la página de error

    En nuestra carpeta de vistas, creamos un error.ejsarchivo:

    h1Error Page/h1p%= error %/p

    Construyendo la página de inicio

    En nuestra carpeta de vistas, creamos un home.ejsarchivo:

    %- include('./partials/menu') %h1 Welcome to the Home Page/h1

    Construyendo la página de inicio de sesión

    En nuestra carpeta de vistas, creamos un login.ejsarchivo:

    div %- include ('./partials/message') % h3 Login Form /h3 form action="/users/login" method="POST" div labelEmail/label input type="email" name="email" placeholder="Email address" /div div labelPassword/label input type="password" name="password" placeholder="Password" /div button type="submit"Login/button /form/div

    Construyendo la página de verificación

    En nuestra carpeta de vistas, creamos un login.ejsarchivo:

    %- include ('./partials/message') %h1Verify page/h1pplease verify your account/pform action="/users/verify" method="POST" div labelverification code/label input type="text" type="number" name="verifyCode" placeholder="code" /div button type="submit"Verify/button/formbra href="/users/resend"Resend Code/a

    Aquí, proporcionamos un formulario para que los usuarios ingresen el código de verificación que se les enviará.

    Creación de la página de registro

    Necesitamos obtener el número de móvil del usuario y todos sabemos que los códigos de país difieren de un país a otro. Por lo tanto, usaremos el [intl-tel-input](https://intl-tel-input.com/)para ayudarnos con los códigos de país y la validación de números de teléfono.

     

    npm install intl-tel-input
    1. En nuestra carpeta pública, creamos un cssdirectorio, jsdirectorio y imgdirectorio:

      cd publicmkdir css js img
    2. Copiamos el intlTelInput.cssarchivo del node_modulesintl-tel-inputbuildcssarchivo a nuestro public/cssdirectorio.

    3. Copiamos tanto la carpeta intlTelInput.jscomo utils.jsla de node_modulesintl-tel-inputbuildjsen nuestro public/jsdirectorio.

    4. Copiamos tanto la carpeta flags.pngcomo [email protected]la de node_modulesintl-tel-inputbuildimgen nuestro public/imgdirectorio.

    Creamos un app.css en nuestra public/csscarpeta:

    cd publictouch app.css

    En app.css, agregue los estilos a continuación:

    .iti__flag {background-image: url("/static/img/flags.png");} @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { .iti__flag {background-image: url("/static/img/[email protected]");}}.hide { display: none}.error { color: red; outline: 1px solid red;}.success{ color: green;}

    Finally, we create a signup.ejs file in our views folder:

    div %- include ('./partials/message') % h3 Signup Form /h3 form action="/users/signup" method="POST" div labelName/label input type="text" name="name" placeholder="name" /div div labelUsername/label input type="text" name="username" placeholder="username" /div div labelPassword/label input type="password" name="password" placeholder="Password" /div div labelPhone number/label input type="tel" id='phone' span✓ Valid/span span/span /div div labelEmail/label input type="email" name="email" placeholder="Email address" /div button type="submit"Sign up/button /form/divscript src="/static/js/intlTelInput.js"/scriptscript const input = document.querySelector("#phone") const errorMsg = document.querySelector("#error-msg") const validMsg = document.querySelector("#valid-msg") const errorMap = ["Invalid number", "Invalid country code", "Too short", "Too long", "Invalid number"]; const iti = window.intlTelInput(input, { separateDialCode: true, autoPlaceholder: "aggressive", hiddenInput: "phonenumber", utilsScript: "/static/js/utils.js?1590403638580" // just for formatting/placeholders etc }); var reset = function() { input.classList.remove("error"); errorMsg.innerHTML = ""; errorMsg.classList.add("hide"); validMsg.classList.add("hide"); }; // on blur: validate input.addEventListener('blur', function() { reset(); if (input.value.trim()) { if (iti.isValidNumber()) { validMsg.classList.remove("hide"); } else { input.classList.add("error"); var errorCode = iti.getValidationError(); errorMsg.innerHTML = errorMap[errorCode]; errorMsg.classList.remove("hide"); } } }); // on keyup / change flag: reset input.addEventListener('change', reset); input.addEventListener('keyup', reset); document.querySele 




    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Autenticación de Node.js con Twilio Verify

    Autenticación de Node.js con Twilio Verify

    ¡Registro! Patrones de diseño para interfaces de IA, con Vitaly Friedman Índice ¿Qué hay de malo con

    programar

    es

    https://pseint.es/static/images/programar-autenticacion-de-node-1158-0.jpg

    2024-04-04

     

    Autenticación de Node.js con Twilio Verify
    Autenticación de Node.js con Twilio Verify

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20