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>