Saltar al contenido principal
El script Create implementa la función definida cuando se crea un usuario. Recomendamos llamar a esta función create. Este script es opcional. Si está habilitado, cuando un usuario se registra a través de o se crea a través de o Auth0 , Auth0 ejecutará el script para crear el registro de usuario correspondiente en la base de datos externa. Cuando se crea un usuario en Auth0, Auth0 invoca una serie de scripts:
  1. Get User: Verifica que el usuario no exista ya en Auth0 ni en la base de datos externa.
  2. Create: Crea el usuario en la base de datos externa.
  3. Login: Verifica que el usuario se haya creado correctamente.

Función create

La función create debe:
  • Enviar los datos del perfil del usuario a la API de la base de datos externa.
  • Devolver un error si la operación de creación del usuario falla.

Definición

La función create acepta dos parámetros y devuelve una función de callback:
create(user, callback): function
ParámetroDescripción
userObjeto. Contiene datos del perfil del usuario obtenidos del proceso de creación del usuario.
callbackFunción. Se usa para pasar datos de error a través del pipeline.

Ejemplo

Este es un ejemplo en pseudo-JavaScript de cómo podría implementar la función create. Para ver ejemplos específicos de cada lenguaje, consulte Ejemplos de scripts específicos de cada lenguaje.
function create(user, callback) {
  // Enviar datos del perfil de usuario a la API de base de datos externa
  let hashedPassword = hash(user.password);

  let options = {
    url: "https://example.com/api/create",
    body: {
      email: user.email,
      username: user.username,
      password: hashedPassword
    }
  };

  send(options, err => {
    // Devolver error en el callback si el usuario ya existe
    if (err && err.id === "USER_ALREADY_EXISTS") {
      return callback(new ValidationError("user_exists", "My custom error message."));
    } else if (err) {
      // Devolver error en el callback si se produjo un error
      return callback(new Error("My custom error message."));
    }

    // Devolver el valor `null` en el callback si la operación de creación de usuario se realizó correctamente
    return callback(null);
  });
}

Cifrado

Evite registrar, almacenar o transportar la credencial de contraseña en ningún lugar en su forma sin cifrar.
Cifre el valor de la contraseña con una biblioteca de hash criptográfico como bcrypt para evitar cualquier posible filtración de datos.

Ejemplo

bcrypt.hash(password, 10, function (err, hash) {
    if (err) {
        return callback(err);
    } else {
        // Devolver contraseña cifrada
    }
});

Función de callback

La función callback acepta un parámetro y devuelve una función.

Definición

callback(error): function
ParámetroTipoObligatorioDescripción
errorObjectObligatorioContiene los datos del error.

Devolver un resultado exitoso

Si la operación de creación del usuario se realizó correctamente, devuelve la función callback y pasa un valor null en el parámetro error.

Ejemplo

return callback(null);

Devolver un error

Si se produce un error, devuelve la función de callback y pasa al parámetro error la información pertinente sobre el error.

Objeto de error de tipo ValidationError

El objeto de error personalizado ValidationError le permite pasar datos que se mostrarán en los registros del Tenant.
Constructor
El constructor ValidationError acepta un máximo de dos parámetros:
new ValidationError(errorCode[, message]): ValidationError
ParámetroDescripción
errorCode(Obligatorio) String. Especifica el tipo de error.
message(Opcional) String. Contiene información sobre el error.

Devolver un error que indica que el usuario ya existe

Si devuelve un error con el valor user_exists para el parámetro errorCode, Auth0 registrará un evento fs en el registro del inquilino.
Ejemplo
return callback(new ValidationError("user_exists", "My custom error message."));
Campo del evento de registro del TenantValor
Codefs
EventoError en el registro
DescripciónMi mensaje de error personalizado.

Parámetro del objeto user

El parámetro del objeto user contiene un conjunto predefinido de propiedades obtenidas del proceso de creación del usuario:
PropiedadDescripción
client_idEl ID de cliente de la aplicación de Auth0 si el usuario se registró mediante Universal Login, o la clave de API si el usuario se creó mediante Auth0 Dashboard o Management API.
tenantEl nombre del inquilino de Auth0.
emailLa dirección de correo electrónico del usuario.
passwordLa contraseña del usuario en texto sin formato.
usernameEl username del usuario. Solo es obligatorio si la conexión de base de datos personalizada tiene habilitada la opción Requires Username.
connectionEl nombre de la conexión de Auth0.
user_metadataContiene las propiedades del objeto user_metadata en el perfil de Auth0 del usuario, si existe.
app_metadataContiene las propiedades del objeto app_metadata en el perfil de Auth0 del usuario, si existe.

Propiedad username

Si tu conexión de base de datos personalizada tiene habilitada la opción Requires Username, los scripts de Login y Get User deben admitir la propiedad username, por lo que debes almacenarla en tu base de datos externa.

Metadatos del usuario y de la aplicación

No es necesario almacenar las propiedades user_metadata y app_metadata en su base de datos externa. Auth0 almacena automáticamente estos valores como parte del registro de perfil del usuario que crea internamente.

Campos de registro personalizados

Si crea y usa campos personalizados durante el proceso de registro, se incluirán en el objeto user.

Ejemplo

{
    client_id: "8tkMo6n1QkKOazqPcSQd8wU7LzXYibgK",
    tenant: "{yourAuth0Tenant}",
    email: "username@domain.com",
    password: "mySuperSecretPassword123",
    username: "username456",
    user_metadata: {
        "language": "en"
    },
    app_metadata: {
        "plan": "full"
    }
}

Ejemplos de scripts según el lenguaje

Auth0 proporciona scripts de ejemplo para usarlos con los siguientes lenguajes/tecnologías:

JavaScript

function create(user, callback) {
  // Este script debe crear una entrada de usuario en su base de datos existente. Se
  // ejecutará cuando un usuario intente registrarse, o cuando se cree un usuario
  // a través del Auth0 Dashboard o la Management API.
  // Cuando este script termine de ejecutarse, el script de Login se
  // ejecutará inmediatamente después para verificar que el usuario fue creado
  // correctamente.
  //
  // El objeto user siempre contendrá las siguientes propiedades:
  // * email: el correo electrónico del usuario
  // * password: la contraseña introducida por el usuario, en texto plano
  // * tenant: el nombre de esta cuenta de Auth0
  // * client_id: el ID de cliente de la aplicación donde el usuario se registró, o
  //              la clave de API si fue creado a través de la Management API o el Auth0 Dashboard
  // * connection: el nombre de esta conexión de base de datos
  //
  // Hay tres formas en que este script puede finalizar:
  // 1. El usuario fue creado correctamente
  //     callback(null);
  // 2. Este usuario ya existe en su base de datos
  //     callback(new ValidationError("user_exists", "my error message"));
  // 3. Algo salió mal al intentar conectarse a su base de datos
  //     callback(new Error("my error message"));
  const msg = 'Please implement the Create script for this database connection ' +
    'at https://manage.auth0.com/#/connections/database';
  return callback(new Error(msg));
}

Proveedor de membresía de ASP.NET (MVC3 - Proveedores universales)

function create(user, callback) {
  const crypto = require('crypto');
  const sqlserver = require('tedious@1.11.0');
  const Connection = sqlserver.Connection;
  const Request = sqlserver.Request;
  const TYPES = sqlserver.TYPES;
  const connection = new Connection({
    userName: 'the username',
    password: 'the password',
    server: 'the server',
    options: {
      database: 'the db name',
      encrypt: true,
      // Necesario para recuperar el userId requerido para la creación de la entidad Membership
      rowCollectionOnRequestCompletion: true
    }
  });
  const applicationId = 'your-application-id-goes-here';
  /**
   * hashPassword
   *
   * Esta función crea una versión cifrada de la contraseña para almacenar en la base de datos.
   *
   * @password  {[string]}      la contraseña ingresada por el usuario
   * @return    {[string]}      la contraseña cifrada
   */
  function hashPassword(password, salt) {
    // la implementación predeterminada usa HMACSHA256 y dado que la longitud de la clave es 64
    // y el salt predeterminado es de 16 bytes, Membership llenará el búfer repitiendo el salt
    const key = Buffer.concat([salt, salt, salt, salt]);
    const hmac = crypto.createHmac('sha256', key);
    hmac.update(Buffer.from(password, 'ucs2'));
    return hmac.digest('base64');
  }
  connection.on('debug', function(text) {
    // si tiene problemas de conexión, descomente esto para obtener información más detallada
    // console.log(text);
  }).on('errorMessage', function(text) {
    // esto mostrará cualquier error al conectarse a la base de datos SQL o con las sentencias SQL
    console.log(JSON.stringify(text));
  });
  connection.on('connect', function(err) {
    if (err) {
      return callback(err);
    }
    createMembershipUser(user, function(err, user) {
      if (err) return callback(err); // esto devolverá un 500
      if (!user) return callback(); // esto devolverá un 401
      callback(null, user);
    });
  });
  function createMembershipUser(user, callback) {
    const userData = {
      UserName: user.email,
      ApplicationId: applicationId
    };
    const createUser =
      'INSERT INTO Users (UserName, LastActivityDate, ApplicationId, UserId, IsAnonymous) ' +
      'OUTPUT Inserted.UserId ' +
      'VALUES (@UserName, GETDATE(), @ApplicationId, NEWID(), \'false\')';
    const createUserQuery = new Request(createUser, function(err, rowCount, rows) {
      if (err) return callback(err);
      // No se agregaron registros
      if (rowCount === 0) return callback(null);
      const userId = rows[0][0].value;
      const salt = crypto.randomBytes(16);
      const membershipData = {
        ApplicationId: applicationId,
        Email: user.email,
        Password: hashPassword(user.password, salt),
        PasswordSalt: salt.toString('base64'),
        UserId: userId
      };
      const createMembership =
        'INSERT INTO Memberships (ApplicationId, UserId, Password, PasswordFormat, ' +
        'PasswordSalt, Email, isApproved, isLockedOut, CreateDate, LastLoginDate, ' +
        'LastPasswordChangedDate, LastLockoutDate, FailedPasswordAttemptCount, ' +
        'FailedPasswordAttemptWindowStart, FailedPasswordAnswerAttemptCount, ' +
        'FailedPasswordAnswerAttemptWindowsStart) ' +
        'VALUES ' +
        '(@ApplicationId, @UserId, @Password, 1, @PasswordSalt, ' +
        '@Email, \'false\', \'false\', GETDATE(), GETDATE(), GETDATE(), GETDATE(), 0, 0, 0, 0)';
      const createMembershipQuery = new Request(createMembership, function(err, rowCount) {
        if (err) return callback(err);
        if (rowCount === 0) return callback(null);
        callback(null, rowCount > 0);
      });
      createMembershipQuery.addParameter('ApplicationId', TYPES.VarChar, membershipData.ApplicationId);
      createMembershipQuery.addParameter('Email', TYPES.VarChar, membershipData.Email);
      createMembershipQuery.addParameter('Password', TYPES.VarChar, membershipData.Password);
      createMembershipQuery.addParameter('PasswordSalt', TYPES.VarChar, membershipData.PasswordSalt);
      createMembershipQuery.addParameter('UserId', TYPES.VarChar, membershipData.UserId);
      connection.execSql(createMembershipQuery);
    });
    createUserQuery.addParameter('UserName', TYPES.VarChar, userData.UserName);
    createUserQuery.addParameter('ApplicationId', TYPES.VarChar, userData.ApplicationId);
    connection.execSql(createUserQuery);
  }
}

Proveedor de membresía de ASP.NET (MVC4 - Simple Membership)

function create(user, callback) {
  const crypto = require('crypto');
  const sqlserver = require('tedious@1.11.0');
  const Connection = sqlserver.Connection;
  const Request = sqlserver.Request;
  const TYPES = sqlserver.TYPES;
  const connection = new Connection({
    userName: 'the username',
    password: 'the password',
    server: 'the server',
    options: {
      database: 'the db name',
      encrypt: true,
      // Necesario para recuperar el userId requerido para la creación de la entidad Membership
      rowCollectionOnRequestCompletion: true
    }
  });
  /**
   * hashPassword
   *
   * Esta función genera el hash de una contraseña utilizando el algoritmo HMAC SHA256.
   *
   * @password    {[string]}    contraseña a la que se le aplicará el hash
   * @salt        {[string]}    salt que se utilizará en el proceso de hash
   * @callback    {[function]}  callback que se invocará tras generar el hash de la contraseña
   */
  function hashPassword(password, salt, callback) {
    const iterations = 1000;
    const passwordHashLength = 32;
    crypto.pbkdf2(password, salt, iterations, passwordHashLength, 'sha1', function (err, hashed) {
      if (err) return callback(err);
      const result = Buffer.concat([Buffer.from([0], 1), salt, Buffer.from(hashed, 'binary')]);
      const resultBase64 = result.toString('base64');
      callback(null, resultBase64);
    });
  }
  connection.on('debug', function (text) {
    // si tiene problemas de conexión, descomente esta línea para obtener información más detallada
    // console.log(text);
  }).on('errorMessage', function (text) {
    // esto mostrará cualquier error al conectarse a la base de datos SQL o al ejecutar sentencias SQL
    console.log(JSON.stringify(text));
  });
  connection.on('connect', function (err) {
    if (err) return callback(err);
    const createUser =
      'INSERT INTO UserProfile (UserName) ' +
      'OUTPUT Inserted.UserId ' +
      'VALUES (@UserName)';
    const createUserQuery = new Request(createUser, function (err, rowCount, rows) {
      if (err || rowCount === 0) return callback(err);
      const userId = rows[0][0].value;
      const salt = crypto.randomBytes(16);
      const createMembership =
        'INSERT INTO webpages_Membership ' +
        '(UserId, CreateDate, IsConfirmed, PasswordFailuresSinceLastSuccess, Password, PasswordSalt) ' +
        'VALUES ' +
        '(@UserId, GETDATE(), \'false\', 0, @Password, \'\')';
      const createMembershipQuery = new Request(createMembership, function (err, rowCount) {
        if (err || rowCount === 0) return callback(err);
        callback(null, rowCount > 0);
      });
      hashPassword(user.password, salt, function (err, hashedPassword) {
        if (err) return callback(err);
        createMembershipQuery.addParameter('Password', TYPES.VarChar, hashedPassword);
        createMembershipQuery.addParameter('PasswordSalt', TYPES.VarChar, salt.toString('base64'));
        createMembershipQuery.addParameter('UserId', TYPES.VarChar, userId);
        connection.execSql(createMembershipQuery);
      });
    });
    createUserQuery.addParameter('UserName', TYPES.VarChar, user.email);
    connection.execSql(createUserQuery);
  });
}

MongoDB

function create(user, callback) {
  const bcrypt = require('bcrypt');
  const MongoClient = require('mongodb@3.1.4').MongoClient;
  const client = new MongoClient('mongodb://user:pass@mymongoserver.com');
  client.connect(function (err) {
    if (err) return callback(err);
    const db = client.db('db-name');
    const users = db.collection('users');
    users.findOne({ email: user.email }, function (err, withSameMail) {
      if (err || withSameMail) {
        client.close();
        return callback(err || new Error('the user already exists'));
      }
      bcrypt.hash(user.password, 10, function (err, hash) {
        if (err) {
          client.close();
          return callback(err);
        }
        user.password = hash;
        users.insert(user, function (err, inserted) {
          client.close();
          if (err) return callback(err);
          callback(null);
        });
      });
    });
  });
}

MySQL

function create(user, callback) {
  const mysql = require('mysql');
  const bcrypt = require('bcrypt');
  const connection = mysql({
    host: 'localhost',
    user: 'me',
    password: 'secret',
    database: 'mydb'
  });
  connection.connect();
  const query = 'INSERT INTO users SET ?';
  bcrypt.hash(user.password, 10, function(err, hash) {
    if (err) return callback(err);
    const insert = {
      password: hash,
      email: user.email
    };
    connection.query(query, insert, function(err, results) {
      if (err) return callback(err);
      if (results.length === 0) return callback();
      callback(null);
    });
  });
}

PostgreSQL

function create(user, callback) {
  //este ejemplo usa la librería "pg"
  //más información aquí: https://github.com/brianc/node-postgres
  const bcrypt = require('bcrypt');
  const postgres = require('pg');
  const conString = 'postgres://user:pass@localhost/mydb';
  postgres.connect(conString, function (err, client, done) {
    if (err) return callback(err);
    bcrypt.hash(user.password, 10, function (err, hashedPassword) {
      if (err) return callback(err);
      const query = 'INSERT INTO users(email, password) VALUES ($1, $2)';
      client.query(query, [user.email, hashedPassword], function (err, result) {
        // NOTA: siempre llama a `done()` aquí para cerrar
        // la conexión a la base de datos
        done();
        return callback(err);
      });
    });
  });
}

SQL Server

function create(user, callback) {
  //este ejemplo usa la biblioteca "tedious"
  //más información aquí: http://pekim.github.io/tedious/index.html
  const bcrypt = require('bcrypt');
  const sqlserver = require('tedious@1.11.0');
  const Connection = sqlserver.Connection;
  const Request = sqlserver.Request;
  const TYPES = sqlserver.TYPES;
  const connection = new Connection({
    userName:  'test',
    password:  'test',
    server:    'localhost',
    options:  {
      database: 'mydb'
    }
  });
  const query = 'INSERT INTO dbo.Users SET Email = @Email, Password = @Password';
  connection.on('debug', function(text) {
    console.log(text);
  }).on('errorMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  }).on('infoMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  });
  connection.on('connect', function (err) {
    if (err) return callback(err);
    const request = new Request(query, function (err, rows) {
      if (err) return callback(err);
      callback(null);
    });
    bcrypt.hash(user.password, 10, function(err, hash) {
      if (err) return callback(err);
      request.addParameter('Email', TYPES.VarChar, user.email);
      request.addParameter('Password', TYPES.VarChar, hash);
      connection.execSql(request);
    });
  });
}

Base de datos SQL de Windows Azure

function create (user, callback) {
  //este ejemplo usa la librería "tedious"
  //más información aquí: http://pekim.github.io/tedious/index.html
  var Connection = require('tedious@1.11.0').Connection;
  var Request = require('tedious@1.11.0').Request;
  var TYPES = require('tedious@1.11.0').TYPES;
  var bcrypt = require('bcrypt');
  var connection = new Connection({
    userName:  'your-user@your-server-id.database.windows.net',
    password:  'the-password',
    server:    'your-server-id.database.windows.net',
    options:  {
      database: 'mydb',
      encrypt:  true
    }
  });
  var query = "INSERT INTO users (Email, Password) VALUES (@Email, @Password)";
  connection.on('debug', function(text) {
    // Descomenta la siguiente línea para habilitar los mensajes de depuración
    // console.log(text);
  }).on('errorMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  }).on('infoMessage', function(text) {
    // Descomenta la siguiente línea para habilitar los mensajes de información
    // console.log(JSON.stringify(text, null, 2));
  });
  connection.on('connect', function (err) {
    if (err) { return callback(err); }
    var request = new Request(query, function (err, rows) {
      if (err) { return callback(err); }
      console.log('rows: ' + rows);
      callback(null);
    });
    bcrypt.hash(user.password, 10, function (err, hashedPassword) {
      if (err) { return callback(err); }
      request.addParameter('Email', TYPES.VarChar, user.email);
      request.addParameter('Password', TYPES.VarChar, hashedPassword);
      connection.execSql(request);
    });
  });
}

Solicitud con autenticación básica

function create(user, callback) {
  const request = require('request');
  request.post({
    url: 'https://myserviceurl.com/users',
    json: user
    //para más opciones, consulta:
    //https://github.com/mikeal/request#requestoptions-callback
  }, function(err, response, body) {
    if (err) return callback(err);
    callback(null);
  });
}

Solución de problemas

Si no puede crear un usuario ni en su base de datos heredada ni en Auth0:
  1. Revise las sentencias console.log() con Actions Real-Time Logs.
  2. Busque al usuario en su base de datos heredada y elimínelo según corresponda. Si el estado parcial del usuario está en Auth0, use el endpoint Delete a User o el endpoint Delete a Connection User de la Management API.
  3. Asegúrese de que Import Mode esté deshabilitado y luego configure el script de creación.

Más información