Passer au contenu principal
Le script Create exécute la fonction définie lorsqu’un utilisateur est créé. Nous recommandons de nommer cette fonction create. Ce script est facultatif. S’il est activé, lorsqu’un utilisateur s’inscrit par l’entremise de ou est créé au moyen de l’ ou d’Auth0 , Auth0 exécute le script pour créer un enregistrement utilisateur correspondant dans la base de données externe. Lorsqu’un utilisateur est créé dans Auth0, Auth0 appelle une série de scripts :
  1. Get User : vérifie que l’utilisateur n’existe pas déjà dans Auth0 ou dans la base de données externe.
  2. Create : crée l’utilisateur dans la base de données externe.
  3. Login : vérifie que l’utilisateur a bien été créé.

Fonction create

La fonction create doit :
  • Envoyer les données de profil de l’utilisateur à l’API de la base de données externe.
  • Renvoyer une erreur si l’opération de création de l’utilisateur a échoué.

Définition

La fonction create prend deux paramètres et renvoie une fonction callback :
create(user, callback): function
ParamètreDescription
userObjet. Contient les données de profil de l’utilisateur issues du processus de création de l’utilisateur.
callbackFonction. Utilisée pour transmettre les données d’erreur via le pipeline.

Exemple

Voici un exemple en pseudo-JavaScript montrant comment vous pourriez implémenter la fonction create. Pour des exemples propres à un langage particulier, consultez Exemples de scripts propres à un langage.
function create(user, callback) {
  // Envoyer les données du profil utilisateur à l'API de base de données externe
  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 => {
    // Retourner une erreur dans le callback si l'utilisateur existe déjà
    if (err && err.id === "USER_ALREADY_EXISTS") {
      return callback(new ValidationError("user_exists", "My custom error message."));
    } else if (err) {
      // Retourner une erreur dans le callback si une erreur s'est produite
      return callback(new Error("My custom error message."));
    }

    // Retourner la valeur `null` dans le callback si l'opération de création d'utilisateur a réussi
    return callback(null);
  });
}

Chiffrement

Évitez de consigner, de stocker ou de transmettre le mot de passe sous forme non chiffrée, où que ce soit.
Chiffrez la valeur du mot de passe à l’aide d’une bibliothèque de hachage cryptographique telle que bcrypt afin d’éviter toute fuite potentielle de données.

Exemple

bcrypt.hash(password, 10, function (err, hash) {
    if (err) {
        return callback(err);
    } else {
        // Retourner le mot de passe haché
    }
});

Fonction de rappel

La fonction callback accepte un paramètre et renvoie une fonction.

Définition

callback(error): function
ParamètreTypeObligatoireDescription
errorObjetObligatoireContient des données d’erreur.

Retourner une réussite

Si l’opération de création de l’utilisateur a réussi, retournez la fonction callback et transmettez une valeur null pour le paramètre error.

Exemple

return callback(null);

Renvoyer une erreur

Si une erreur se produit, appelez la fonction de rappel et transmettez les renseignements pertinents sur l’erreur au paramètre error.

Objet du type ValidationError

L’objet d’erreur personnalisée de type ValidationError vous permet de transmettre des données qui seront affichées dans les journaux du locataire.
Constructeur
Le constructeur ValidationError accepte jusqu’à deux paramètres :
new ValidationError(errorCode[, message]): ValidationError
ParamètreDescription
errorCode(Obligatoire) Chaîne. Indique le type d’erreur.
message(Facultatif) Chaîne. Contient des informations sur l’erreur.

Retourner une erreur indiquant que l’utilisateur existe déjà

Si vous retournez une erreur avec la valeur user_exists pour le paramètre errorCode, Auth0 enregistrera un événement de journal fs pour le locataire.
Exemple
return callback(new ValidationError("user_exists", "My custom error message."));
Champ de l’événement du journal du locataireValeur
Codefs
ÉvénementÉchec de l’inscription
DescriptionMy custom error message.

Paramètre de l’objet utilisateur

Le paramètre d’objet user contient un ensemble prédéfini de propriétés issues du processus de création de l’utilisateur :
PropriétéDescription
client_idL’ID client de l’application Auth0 si l’utilisateur s’est inscrit au moyen d’Universal Login, ou la clé API si l’utilisateur a été créé au moyen de l’Auth0 Dashboard ou de la Management API.
tenantLe nom du locataire Auth0.
emailL’adresse courriel de l’utilisateur.
passwordLe mot de passe de l’utilisateur en texte brut.
usernameLe nom d’utilisateur de l’utilisateur. Obligatoire uniquement si le paramètre Nom d’utilisateur requis est activé pour la connexion à la base de données personnalisée.
connectionLe nom de la connexion Auth0.
user_metadataContient les propriétés de l’objet user_metadata dans le profil Auth0 de l’utilisateur, si l’objet existe.
app_metadataContient les propriétés de l’objet app_metadata dans le profil Auth0 de l’utilisateur, si l’objet existe.

Propriété username

Si le paramètre nom d’utilisateur requis est activé pour votre connexion de base de données personnalisée, les scripts Login et Get User doivent prendre en charge la propriété username; vous devez donc la stocker dans votre base de données externe.

Métadonnées de l’utilisateur et de l’application

Les propriétés user_metadata et app_metadata n’ont pas besoin d’être stockées dans votre base de données externe. Auth0 stocke automatiquement ces valeurs dans l’enregistrement du profil utilisateur créé en interne.

Champs d’inscription personnalisés

Si vous créez et utilisez des champs personnalisés lors de l’inscription, ils seront inclus dans l’objet user.

Exemple

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

Exemples de scripts par langage

Auth0 fournit des scripts d’exemple pour les langages/technologies suivants :

JavaScript

function create(user, callback) {
  // Ce script doit créer une entrée d'utilisateur dans votre base de données existante. Il sera
  // exécuté lorsqu'un utilisateur tente de s'inscrire, ou lorsqu'un utilisateur est créé
  // via le Auth0 Dashboard ou la Management API.
  // Une fois l'exécution de ce script terminée, le script Login sera
  // exécuté immédiatement après pour vérifier que l'utilisateur a bien été créé.
  //
  // L'objet utilisateur contiendra toujours les propriétés suivantes :
  // * email: le courriel de l'utilisateur
  // * password: le mot de passe saisi par l'utilisateur, en texte brut
  // * tenant: le nom de ce compte Auth0
  // * client_id: l'ID client de l'application où l'utilisateur s'est inscrit, ou
  //              la clé API si créé via la Management API ou le Auth0 Dashboard
  // * connection: le nom de cette connexion de base de données
  //
  // Ce script peut se terminer de trois façons :
  // 1. Un utilisateur a été créé avec succès
  //     callback(null);
  // 2. Cet utilisateur existe déjà dans votre base de données
  //     callback(new ValidationError("user_exists", "my error message"));
  // 3. Une erreur s'est produite lors de la tentative d'accès à votre base de données
  //     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));
}

ASP.NET Membership Provider (MVC3 - fournisseurs universels)

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,
      // Required to retrieve userId needed for Membership entity creation
      rowCollectionOnRequestCompletion: true
    }
  });
  const applicationId = 'your-application-id-goes-here';
  /**
   * hashPassword
   *
   * Cette fonction crée une version hachée du mot de passe à stocker dans la base de données.
   *
   * @password  {[string]}      le mot de passe saisi par l'utilisateur
   * @return    {[string]}      le mot de passe haché
   */
  function hashPassword(password, salt) {
    // the default implementation uses HMACSHA256 and since Key length is 64
    // and default salt is 16 bytes, Membership will fill the buffer repeating the 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) {
    // if you have connection issues, uncomment this to get more detailed info
    // console.log(text);
  }).on('errorMessage', function(text) {
    // this will show any errors when connecting to the SQL database or with the SQL statements
    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); // this will return a 500
      if (!user) return callback(); // this will return a 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 records added
      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);
  }
}

ASP.NET Membership Provider (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,
      // Required to retrieve userId needed for Membership entity creation
      rowCollectionOnRequestCompletion: true
    }
  });
  /**
   * hashPassword
   *
   * Cette fonction hache un mot de passe à l'aide de l'algorithme HMAC SHA256.
   *
   * @password    {[string]}    mot de passe à hacher
   * @salt        {[string]}    sel à utiliser dans le processus de hachage
   * @callback    {[function]}  callback à appeler après le hachage du mot de passe
   */
  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) {
    // if you have connection issues, uncomment this to get more detailed info
    // console.log(text);
  }).on('errorMessage', function (text) {
    // this will show any errors when connecting to the SQL database or with the SQL statements
    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) {
  //cet exemple utilise la bibliothèque "pg"
  //plus d'informations ici : 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) {
        // REMARQUE : appelez toujours `done()` ici pour fermer
        // la connexion à la base de données
        done();
        return callback(err);
      });
    });
  });
}

SQL Server

function create(user, callback) {
  //cet exemple utilise la bibliothèque "tedious"
  //plus d'informations ici : 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 données SQL de Windows Azure

function create (user, callback) {
  //cet exemple utilise la bibliothèque "tedious"
  //plus d'informations ici : 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) {
    // Décommenter la ligne suivante pour activer les messages de débogage
    // console.log(text);
  }).on('errorMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  }).on('infoMessage', function(text) {
    // Décommenter la ligne suivante pour activer les messages d'information
    // 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);
    });
  });
}

Requête avec authentification Basic Auth

function create(user, callback) {
  const request = require('request');
  request.post({
    url: 'https://myserviceurl.com/users',
    json: user
    //pour plus d'options, voir :
    //https://github.com/mikeal/request#requestoptions-callback
  }, function(err, response, body) {
    if (err) return callback(err);
    callback(null);
  });
}

Dépannage

Si vous ne parvenez pas à créer un utilisateur dans votre base de données héritée ou dans Auth0 :
  1. Vérifiez les messages console.log() dans les journaux en temps réel d’Actions.
  2. Trouvez l’utilisateur dans votre base de données héritée et supprimez-le au besoin. Si un état utilisateur partiel se trouve dans Auth0, utilisez le point de terminaison Delete a User ou Delete a Connection User de la Management API.
  3. Assurez-vous que Import Mode est désactivé, puis configurez le script de création.

En savoir plus