¿Qué es AccountKit?
AccountKit permite que las personas se registren en tu aplicación e inicien sesión en ella únicamente usando un número de teléfono o una dirección de correo electrónico, sin necesidad de una contraseña.
AccountKit usa la infraestructura de envío de correos electrónicos y SMS de Facebook.
Account Kit NO requiere una cuenta de Facebook
AccountKit NO requiere una cuenta de Facebook, por lo que ganas mas usuarios en tu plataforma, todos aquellos que no se sienten cómodos otorgándote los permisos de su red social personal.
¿Cómo funciona?
- Accoun Kit crea una base de datos exclusiva para tu aplicación.
- Una API de REST te permite acceder a los datos en cualquier momento.
- La base de datos se completa con una lista de los números de teléfono o las direcciones de correo electrónico y los identificadores de las cuentas que se pueden usar dentro de la aplicación.
Tokens
- Token de acceso del cliente
- Token de código de autorización
Con el token de acceso de cliente, después de un inicio de sesión correcto, la aplicación del cliente puede recibir directamente un token de acceso de larga duración, que a partir de entonces será el responsable de pasar a tu servidor de manera segura para su utilización en las llamadas a la API.
Con el token de código de autorización, después de un inicio de sesión correcto, la aplicación del cliente recibirá un código de autorización de corta duración, que será entonces responsable de pasar de manera segura a tu servidor.
Este proceso se ofrece como un recurso para disminuir riesgos en los casos en los que un atacante intente hacerse pasar por tu aplicación del cliente o interceptar de algún otro modo el token de acceso de larga duración de la API.
AccountKit SDK para JavaScript admite solo autenticación mediante el código de autorización
El AccountKit SDK para JavaScript para web admite solo la autenticación mediante el código de autorización, por lo que al recibir el token, debes realizar el proceso de intercambio de tokens para las siguientes peticiones que realices.
Te recomendamos incluir un token de acceso en cada solicitud del servidor a tu aplicación y verificar el identificador del usuario desde el token y no directamente desde el cliente. Esto ayudará a proteger tu aplicación de usuarios no autorizados.
Implementar AccountKit para Web con NodeJS
Crear aplicación de FB para AccountKit Web
1. Crea tu cuenta de Facebook Developer
Ingresa a https://developers.facebook.com y confirma tener todo en regla con tu cuenta de desarrollador.
2. Crea una aplicación nueva o selecciona alguna ya existente
En el sitio de implementación de AccountKit https://developers.facebook.com/docs/accountkit/webjs selecciona alguna aplicación que ya tengas o crea una nueva
3. Agrega AccountKit como producto de tu aplicación
Da click en agregar producto
De entre los diferentes productos, selecciona AccountKit
Selecciona la opción de Web
4. Configura tu aplicación
Ingresa a las opciones de configuración de tu aplicación con AccountKit
Decide que tipo de seguridad deseas y da click en Empezar
Es muy importante que indiques la URL de tu sitio, pero también la URL de redirección, es decir, a donde debe mandar AccountKit después de que se logró el login con éxito.
Puedes también configurar si deseas el login solo con SMS o con correo
Implementar código de AccountKit para Web
1. Crea un archivo HTML con el formulario para el login
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>AccountKit 101</title> <script src="https://sdk.accountkit.com/en_US/sdk.js"></script> </head> <body> <main> <!-- Un formulario básico para el login --> <input value="+52" id="country_code" /> <input placeholder="Teléfono" id="phone_number"/> <button onclick="smsLogin();">Iniciar sesión con SMS</button> <div>ó</div> <input placeholder="email" id="email"/> <button onclick="emailLogin();">Iniciar sesión con correo</button> </main> <script> </script> </body> </html> |
Nota en la línea 6 que estamos cargando el SDK de accountKit desde su url, y que no es posible cambiarla a tus propios archivos.
2. Agreguemos las funcionales para el login
Deseamos crear funciones para login SMS y con Correo que ya hemos agregado como acciones en los botones del formulario.
Dentro de las etiquetas script, vamos a inicializar AccountKit SDK
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Iniciar AccountKit SDK // @see https://developers.facebook.com/docs/accountkit/webjs/reference AccountKit_OnInteractive = function() { AccountKit.init( { appId:"{{appId}}", state:"{{csrf}}", version:"{{version}}", fbAppEventsEnabled:true, redirect:"https://{{siteUrl}}/login_success" } ); }; |
Nota que usaremos Mustache para los templates, por lo cual, todo lo que ves entre llaves, son variables que le serán inyectadas desde nuestro server.
Agregaremos entonces el método smsLogin e emailLogin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// Función para el login con SMS // Mando al SDK el login con los datos escritos en el formulario function smsLogin() { const countryCode = document.getElementById('country_code').value; const phoneNumber = document.getElementById('phone_number').value; AccountKit.login( 'PHONE', { countryCode, phoneNumber }, loginCallback ); } // Función para el login con correo // Mando al SDK el login con los datos escritos en el formulario function emailLogin() { console.log('They clicked on login via sms'); const emailAddress = document.getElementById('email').value; AccountKit.login( 'EMAIL', { emailAddress }, loginCallback ); } |
Lo que estamos haciendo es obtener los datos escritos en los inputs, y mandandolos al método login de accountKit.
Nota que también le estamos mandando una función callback. Esa se ejecutará después de que AccountKit nos responda en el intento de login.
3. Creamos la función callback del login
En esta función manejamos los estados que nos regresa AccounKit.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Nuestro método para manejar las respuestas del intento de login function loginCallback(response) { if (response.status === 'PARTIALLY_AUTHENTICATED') { // Agregamos a nuestro formulario "temp" el CSRF y el código que regreso FB document.getElementById('code').value = response.code; document.getElementById('csrf').value = response.state; // Lanzamos el submit para procesar los datos y obtener el nuevo token document.getElementById('login_success').submit(); } else if (response.status === 'NOT_AUTHENTICATED') { // Aqui podemos meter código para manipular el dom e indicar el error } else if (response.status === 'BAD_PARAMS') { // Aqui podemos meter códig'BAD_PARAMS'ular el dom e indicar el error } } |
Nota en las lineas 5 y 6 que estamos accediendo a nuevos elementos del DOM.
4. Agregamos formulario para el CSRF
Estos los debemos agregar justo despues de nuestro formulario actual. La idea es tener un nuevo formulario para poder mandar las respuestas de AccountKit para el telefono y procesar correctamente CSRF y los tokens.
1 2 3 4 5 |
<!-- Nuestro formulario para manejar los tokens --> <form id="login_success" method="post" action="/login_success"> <input id="csrf" type="hidden" name="csrf" /> <input id="code" type="hidden" name="code" /> </form> |
5. Ahora, a trabajar con nuestro servidor
Trabajaremos con NodeJS con ExpressJS usando Mustache para los templates, Request para hacer peticiones al API Graph, Guid para generar una cadena para el CSRF y DotEnv para no publicar nuestros tokens.
Instala los paquetes con
1 |
npm install body-parser dotenv express guid mustache querystring request |
En el archivo server.js (o con el nombre que quieras) iniciala los módulos e inicia la app de express.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
require('dotenv').config(); const fs = require('fs'); const Guid = require('guid'); const express = require('express'); const bodyParser = require('body-parser'); const Mustache = require('mustache'); const Request = require('request'); const Querystring = require('querystring'); const app = express(); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); |
Agreguemos los datos necesarios para AccountKit tenga toda la información requerida
1 2 3 4 5 6 7 8 9 |
// Generate a string for CSRF var csrfGuid = Guid.raw(); // Define values for accountkit const AK_API_VERSION = 'v1.1'; const AK_APP_ID = process.env.FB_APP_ID; const AK_APP_SECRET = process.env.FB_APP_SECRET; const AK_ME_URL = `https://graph.accountkit.com/${AK_API_VERSION}/me`; const AK_TOKEN_URL = `https://graph.accountkit.com/${AK_API_VERSION}/access_token`; |
Los datos que vienen del archivo .env son sensibles, los debes obtener de las configuraciones en FB de tu app.
Agregamos la ruta para mostrar el formulario de login
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Función para cargar la vista function loadLogin() { return fs.readFileSync('views/login.html').toString(); } app.get('/', (request, response) => { const view = { appId: AK_APP_ID, csrf: csrfGuid, version: AK_API_VERSION, siteUrl: process.env.SITE_URL, }; const html = Mustache.to_html(loadLogin(), view); response.send(html); }); |
Cargamos el template y con mustache lo rendereamos. Es aquí donde le estamos mandando las variables que arriba dejamos con los placeholders.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// Función para cargar la vista function loadLoginSuccess() { return fs.readFileSync('views/login_success.html').toString(); } app.post('/login_success', (request, response) => { // CSRF check if (request.body.csrf === csrfGuid) { // Generar el token para la app // @see https://developers.facebook.com/docs/accountkit/accesstokens const appAccessToken = ['AA', AK_APP_ID, AK_APP_SECRET].join('|'); const params = { grant_type: 'authorization_code', code: request.body.code, access_token: appAccessToken, }; // Intercambio de tokens const tokenExchangeUrl = `${AK_TOKEN_URL}?${Querystring.stringify(params)}`; Request.get({ url: tokenExchangeUrl, json: true }, (err, resp, respBody) => { const view = { user_access_token: respBody.access_token, expires_at: respBody.expires_at, user_id: respBody.id, }; // Obtener los detalles de la cuenta loggeada const meEndpointUrl = `${AK_ME_URL}?access_token=${respBody.access_token}`; Request.get({ url: meEndpointUrl, json: true }, (err, resp, respBody) => { // Mandamos ahora si, la vista despues del login if (respBody.phone) { view.phone_num = respBody.phone.number; } else if (respBody.email) { view.email_addr = respBody.email.address; } const html = Mustache.to_html(loadLoginSuccess(), view); response.send(html); }); }); } else { // Manejar el error cuando el CSRF no coincide response.writeHead(200, { 'Content-Type': 'text/html' }); response.end('Something went wrong. :( '); } }); |
En nuestro html del login habíamos definido un callback para el proceso de login, el cual llena los campos del formulario y ejecuta el submit del mismo.
Bien, ese submit llega a nuestro server por post para la ruta login_success, y es ahí donde haremos la otra parte del proceso de login.
Primero, en la línea 8 validamos que el código CSRF que definimos sea el mismo, de este modo confirmamos la seguridad de nuestra aplicación.
Dado que el SDK para Javascript solo acepta tokens de autorización, necesitamos hacer el exchange para obtener el nuevo token con el que trabajaremos las peticiones. El token se debe enviar con cierto formato, que es justo el formato que aplicamos en la linea 11.
En la línea 21 solicitamos el nuevo token, y lo almacenamos para futuras peticiones, como la que hacemos en la línea 30 para obtener los datos de la cuenta.
Por último en la línea 37 rendereamos una vista diferente donde solo estamos mostrando los datos de la cuenta.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!doctype html> <head> <meta charset="utf-8"> <title>AccountKit 101</title> </head> <body> <div>Logged In to Account Kit:</div> <div>User Token: {{user_access_token}}</div> <div>User Token Expires at: {{expires_at}}</div> <div>User Id: {{user_id}}</div> <div>User phone: {{phone_num}}</div> <div>User email: {{email_addr}}</div> </body> |
Puedes ver este código completo en https://github.com/nmicht/accountkit-101
¿Te gustó este artículo?
Si te gustó este artículo, te ha servido o aprendiste algo nuevo; compártelo en tus redes sociales o invítame un cafe.