How to use Passwordless, Database and Social connections in the same classic universal login page

Overview

This article clarifies whether it is possible to use the Classic Universal Login and have the following connections available for a user to choose from:

  • Passwordless
  • Database
  • Social

The Auth0.js/Lock libraries both provide functionality for Database and Passwordless logins, but it may not be clear how to incorporate both connection options into an application.

Solution

The following is a sample solution written with Auth0.js to render a login widget that provides a link to allow members to log in with a passwordless connection as well. This example can serve as a rough guideline for achieving this use case.

NOTE: This also works for embedded login implementations with Auth0.js.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title>Sign In with Auth0</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">;
</head>
  <style>
    body, html {
      height: 100%;
      background-color: #f9f9f9;
    }

    .login-container {
      position: relative;
      height: 100%;
      background-color: #FFFEF4;
    }
    
    #login-modal-box {
      background-color: #ebebeb;
    }

    .login-box {
      width: 320px;
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      padding: 15px;
      background-color: #fff;
      box-shadow: 0px 5px 5px #ccc;
      border-radius: 5px;
      border-top: 1px solid #e9e9e9;
    }

    .login-header {
      text-align: center;
    }

    .login-header img {
      width: 75px;
    }
    
    #btn-login {
      cursor: pointer;
      width: 100%;
      height: 35px;
      display: flex;
      justify-content: center;
      align-items: center;
      border-radius: 5px;
      background-color: #02112A;
      color: #FFFEF4;
    }
    
    #btn-login:hover {
      background-color: #80878F;
      color: #02112A;
    }
    
    #btn-signup {
      display: none;
      cursor: pointer;
      width: 100%;
      height: 35px;
      display: flex;
      justify-content: center;
      align-items: center;
      border-radius: 5px;
      background-color: #FFFEF4;
      border: 1px solid #02112A;
      color: #02112A;
    }
    
    #btn-signup:hover {
      background-color: #80878F;
      border: 1px solid #80878F;
      color: #02112A;
    }
    
    #btn-google {
      cursor: pointer;
      width: 100%;
      height: 35px;
      display: none;
      justify-content: center;
      align-items: center;
      border-radius: 5px;
      background-color: #39D435;
      color: #02112A;
    }
    
    #btn-google:hover {
      background-color: #80878F;
      color: #02112A;
    }

    #error-message {
      display: none;
      white-space: break-spaces;
    }
    
    #switch_login_type_btn_div {
      width: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    #passwordless_info_text {
      display: block;
      color: #02112A;
    }
    
    #switch_to_passwordless_btn {
      display: none;
      cursor: pointer;
      color: #02112A;
    }
    
    #switch_to_passwordless_btn:hover {
      color: #C3C1A8;
    }
    
    #switch_to_usernamepassword_btn {
      display: block;
      cursor: pointer;
      color: #02112A;
    }
    
    #switch_to_usernamepassword_btn:hover {
      color: #C3C1A8;
    }
    
    #password_input_div {
      display: none;
    }
    
    #code_input_div {
      display: none;
    }
  </style>
<body>
  <div class="login-container">
    <div id="login-modal-box" class="col-xs-12 col-sm-4 col-sm-offset-4 login-box">
      <div class="login-header">
        <img src="https://fartheradvisorphotos.s3.amazonaws.com/farther_favicon.png"/>;
        <h3>Welcome</h3>
        <h5>Log In To Farther</h5>
      </div>
      
      <div id="switch_login_type_btn_div">
        <p id="switch_to_passwordless_btn" onclick="switchToPasswordless()">
          Switch to Passwordless ->
        </p>

        <p id="switch_to_usernamepassword_btn" onclick="switchToUsernamePassword()">
          Switch to Username + Password ->
        </p>
      </div>
      
      <div id="error-message" class="alert alert-danger"></div>
      <form onsubmit="return false;" method="post">
        <div id="email_input_div" class="form-group">
         <label for="name">Email</label>
          <input
            type="email"
            class="form-control"
            id="email"
            placeholder="Enter your email">
        </div>
        <div id="password_input_div" class="form-group">
          <label for="name">Password</label>
          <input
            type="password"
            class="form-control"
            id="password"
            placeholder="Enter your password">
        </div>
        <div id="code_input_div" class="form-group">
          <label for="name">Code</label>
          <input
            type="text"
            class="form-control"
            id="code"
            placeholder="Enter your code">
        </div>
        <p id="passwordless_info_text">
          We will send a link to this email
        </p>
        <div class="captcha-container form-group"></div>
        <p
          type="button"
          id="btn-login">
            Log In
        </p>
        <p
          type="button"
          id="btn-signup">
            Sign Up
        </p>
        <hr>
        <p
          type="button"
          id="btn-google">
            Log In with Google
        </p>
      </form>
    </div>
  </div>

  <!--[if IE 8]>
  <script src="//cdnjs.cloudflare.com/ajax/libs/ie8/0.2.5/ie8.js"></script>;
  <![endif]-->

  <!--[if lte IE 9]>
  <script src="https://cdn.auth0.com/js/polyfills/1.0/base64.min.js"></script>;
  <script src="https://cdn.auth0.com/js/polyfills/1.0/es5-shim.min.js"></script>;
  <![endif]-->

  <script src="https://cdn.auth0.com/js/auth0/9.18/auth0.min.js"></script>;
  <script src="https://cdn.auth0.com/js/polyfills/1.0/object-assign.min.js"></script>;
  <script>
    let auth_type_is_passwordless = true;
    let isLoading = false;
    let email_used = '';
    let to_submit_code = false;
    
    function switchToPasswordless() {
      document.getElementById("switch_to_passwordless_btn").style.display = "none";
      document.getElementById("switch_to_usernamepassword_btn").style.display = "block";
      document.getElementById("password_input_div").style.display = "none";
      document.getElementById("passwordless_info_text").style.display = "block";
      document.getElementById("btn-google").style.display = "none";
      auth_type_is_passwordless = true;
    }
      
    function switchToUsernamePassword() {
      document.getElementById("switch_to_passwordless_btn").style.display = "block";
      document.getElementById("switch_to_usernamepassword_btn").style.display = "none";
      document.getElementById("password_input_div").style.display = "block";
      document.getElementById("passwordless_info_text").style.display = "none";
      document.getElementById("passwordless_info_text").innerHTML = "We will send a link to this email";
      document.getElementById("btn-google").style.display = "flex";
      auth_type_is_passwordless = false;
      to_submit_code = false;
      document.getElementById("email_input_div").style.display = "block";
      document.getElementById("code_input_div").style.display = "none";
    }
    
    window.addEventListener('load', function() {

      var config = JSON.parse(
        decodeURIComponent(escape(window.atob('@@config@@')))
      );

      var leeway = config.internalOptions.leeway;
      if (leeway) {
        var convertedLeeway = parseInt(leeway);
      
        if (!isNaN(convertedLeeway)) {
          config.internalOptions.leeway = convertedLeeway;
        }
      }

      var params = Object.assign({
        overrides: {
          __tenant: config.auth0Tenant,
          __token_issuer: config.authorizationServer.issuer
        },
        domain: config.auth0Domain,
        clientID: config.clientID,
        redirectUri: config.callbackURL,
        responseType: 'code'
      }, config.internalOptions);

      var webAuth = new auth0.WebAuth(params);
      var databaseConnection = 'Username-Password-Authentication';
      var captcha = webAuth.renderCaptcha(
        document.querySelector('.captcha-container')
      );
      
      function login() {
        if (!isLoading) {
          isLoading = true;
          if (to_submit_code) {
            submitPasswordlessCode()
          } else {
            if (auth_type_is_passwordless) {
              login_Passwordless();
            } else {
              login_UsernamePassword();
            }
          }
        }
      }
      
      // Passwordless  \/
      
      var webAuth_passwordless = new auth0.WebAuth({
        clientID: config.clientID,
        domain: config.auth0Domain,
        redirectUri: config.callbackURL,
        responseType: 'token id_token'
      });
      
      function login_Passwordless() {
        var email = document.getElementById('email').value;
        
        // set cookie
        let d = new Date();
        d.setTime(d.getTime() + (1*60*1000*525600));
        let expires = "expires=" + d.toUTCString();
        document.cookie = "auth0_email=" + email + ";" + expires + ";path=/;samesite=strict";
        
        webAuth_passwordless.passwordlessStart({
            connection: 'email',
            send: 'link', //code
            email: email
          }, function (err, res) {
            isLoading = false;
            if (err) displayError(err);
          
            if (err) {
              console.log(err);
              document.getElementById("passwordless_info_text").innerHTML = "Apologies, there was an error. Please try again";
            } else {
              /*
              to_submit_code = true;
              document.getElementById("passwordless_info_text").innerHTML = "Code sent! Please check your email";
              document.getElementById("email_input_div").style.display = "none";
              document.getElementById("code_input_div").style.display = "block";
              email_used = email;
              */
              console.log(res);
              document.getElementById("passwordless_info_text").innerHTML = "Link sent! Please check your email";
            }
          }
        );
      }
      
      function submitPasswordlessCode() {
        var code = document.getElementById('code').value;
        webAuth.passwordlessLogin({
          connection: 'email',
          email: email_used,
          verificationCode: code
        }, function (err, res) {
          isLoading = false;
          if (err) {
            document.getElementById("passwordless_info_text").innerHTML = "Error or wrong code. Please try again";
          } else {
            console.log(res);
          }
        });
      }
      
      // Passwordless  /\
      

      function login_UsernamePassword() {
        //e.preventDefault();
        //var button = this;
        var email = document.getElementById('email').value;
        var password = document.getElementById('password').value;
        //button.disabled = true;
        
        // set cookie
        let d = new Date();
        d.setTime(d.getTime() + (1*60*1000*525600));
        let expires = "expires=" + d.toUTCString();
        document.cookie = "auth0_email=" + email + ";" + expires + ";path=/;samesite=strict";
        
        webAuth.login({
          realm: databaseConnection,
          username: email,
          password: password,
          captcha: captcha.getValue()
        }, function(err) {
          isLoading = false;
          if (err) displayError(err);
          //button.disabled = false;
        });
      }

      function signup() {
        if (!isLoading) {
          isLoading = true;
          //var button = this;
          var email = document.getElementById('email').value;
          var password = document.getElementById('password').value;

          // set cookie
          let d = new Date();
          d.setTime(d.getTime() + (1*60*1000*525600));
          let expires = "expires=" + d.toUTCString();
          document.cookie = "auth0_email=" + email + ";" + expires + ";path=/;samesite=strict";

          //button.disabled = true;
          webAuth.redirect.signupAndLogin({
            connection: databaseConnection,
            email: email,
            password: password,
            captcha: captcha.getValue()
          }, function(err) {
            isLoading = false;
            if (err) displayError(err);
            //button.disabled = false;
          });
        }
      }

      function loginWithGoogle() {
        if (!isLoading) {
          isLoading = true;
          webAuth.authorize({
            connection: 'google-oauth2'
          }, function(err) {
            isLoading = false;
            if (err) displayError(err);
          });
        }
      }

      function displayError(err) {
        captcha.reload();
        var errorMessage = document.getElementById('error-message');
        errorMessage.innerHTML = err.policy || err.description;
        errorMessage.style.display = 'block';
      }

      document.getElementById('btn-login').addEventListener('click', login);
      document.getElementById('btn-google').addEventListener('click', loginWithGoogle);
      document.getElementById('btn-signup').addEventListener('click', signup);
    });
  </script>
</body>
</html>