-
-
Save dandrews/0840397492d42e380678a8a598c8b11d to your computer and use it in GitHub Desktop.
Auth0 custom login page example with forgot password
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> | |
<title>Welcome to Growth Book - Sign in or register</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"> | |
<style> | |
@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,300;0,400;0,500;0,600;0,700;1,400&display=swap"); | |
body, html { | |
-webkit-font-smoothing: antialiased; | |
height: 100%; | |
background-color: #f9f9f9; | |
} | |
.login-container { | |
position: relative; | |
height: 100%; | |
} | |
.btn-block { | |
display:block; | |
width: 100%; | |
} | |
.btn-google { | |
color: #545454; | |
background-color: #ffffff; | |
box-shadow: 0 1px 2px 1px #ddd; | |
} | |
.form-group { | |
margin-bottom: 1rem; | |
} | |
.login-box { | |
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; | |
} | |
.error-message { | |
display: none; | |
white-space: break-spaces; | |
} | |
.welcome { | |
z-index: 1000; | |
position: relative; | |
min-height: 100vh; | |
font-family: Poppins, "Helvetica Neue", Arial, sans-serif; | |
} | |
.welcome .intro-side { | |
position:relative; | |
background-color: #4817a1; | |
background: radial-gradient( | |
at 50% 100%, | |
rgba(109, 18, 228, 0.75), | |
rgb(15, 1, 94) | |
); | |
color: #fff; | |
padding-bottom: 30px; | |
vertical-align: middle; | |
min-height: 100%; | |
} | |
.welcome .ghosted-logo { | |
background: transparent url("https://app.growthbook.io/logo/growth-book-logomark-ghosted.png") 50% | |
50%; | |
background-size: contain; | |
background-repeat: no-repeat; | |
min-height: 100%; | |
position: absolute; | |
top: 0; | |
bottom: 0; | |
left: 10px; | |
right: 10px; | |
opacity: 0.5; | |
} | |
.welcome .logo { | |
position: absolute; | |
bottom: 10px; | |
left: 0; | |
right: 0; | |
text-align: center; | |
} | |
.welcome .form-side { | |
background-color: #fff; | |
} | |
.welcome .formwrap { | |
width: 100%; | |
max-width: 500px; | |
} | |
.welcome h1, | |
.welcome h2, | |
.welcome h3 { | |
font-weight: 600; | |
} | |
@media (min-width: 575px) { | |
.welcome .full-height { | |
min-height: 100vh; | |
} | |
.welcome .intro-side { | |
padding-bottom: 0; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div class="welcome container-fluid"> | |
<div class="row full-height align-items-stretch d-flex flex-fill d-flex justify-content-start"> | |
<div class="col-sm-5 intro-side "> | |
<div class="ghosted-logo"></div> | |
<div class="p-sm-1 p-md-3 pt-3 pt-sm-3 pt-md-5 d-flex align-items-center justify-content-center h-100"> | |
<div class="text-center"> | |
<h1 class="title h1">Welcome to Growth Book Cloud!</h1> | |
<p>We're glad you're here</p> | |
<div class="d-none" id="extrainfo"> | |
<p class="h4 mt-4 px-3" style="font-weight:400; font-size: 1.1em"> | |
Get everything you need to start experimenting in as little as 2 minutes using Growth Book cloud - for free!</p> | |
</div> | |
</div> | |
</div> | |
<div class="logo"> | |
<a | |
href="https://www.growthbook.io" | |
target="_blank" | |
rel="noreferrer" | |
> | |
<img | |
src="https://app.growthbook.io/logo/growth-book-logo-white.png" | |
style="max-width: 150px" | |
/> | |
</a> | |
</div> | |
</div> | |
<div class="col-sm-7 form-side p-0"> | |
<div class="welcomemodal p-4 h-100"> | |
<div class="h-100 align-items-center justify-content-center d-flex pr-2"> | |
<div class="formwrap"> | |
<div class="d-none" id="registerform"> | |
<form onsubmit="return false;" method="post"> | |
<div> | |
<h3 class="h2">Register</h3> | |
<p> | |
Already have an account? | |
<a | |
href="#" | |
id="registerSwitcher" | |
> | |
Log In | |
</a> | |
</p> | |
</div> | |
<div class="form-group"> | |
Email Address | |
<input | |
required | |
type="email" | |
name="email" | |
autoFocus="true" | |
autoComplete="username" | |
id="regemail" | |
class="form-control" | |
/> | |
</div> | |
<div class="form-group"> | |
Password | |
<input | |
required | |
type="password" | |
name="password" | |
autoComplete="new-password" | |
minLength="8" | |
class="form-control" | |
id="regpassword" | |
/> | |
</div> | |
<div class="captcha-container form-group"></div> | |
<div class="alert alert-danger error-message form-group"></div> | |
<button | |
class="btn btn-primary btn-block btn-lg mt-4" | |
type="submit" | |
id="btn-signup" | |
> | |
Sign up | |
</button> | |
<hr> | |
<button | |
type="button" | |
id="btn-google" | |
class="btn btn-lg btn-google btn-block btn-outline"> | |
<img src="https://img.icons8.com/color/16/000000/google-logo.png" class="mr-2"> Sign up with Google | |
</button> | |
</form> | |
</div> | |
<div class="loginform" id="loginform"> | |
<form onsubmit="return false;" method="post"> | |
<div> | |
<h3 class="h2">Log In</h3> | |
<p> | |
Don't have an account yet? | |
<a | |
href="#" | |
id="loginSwitcher" | |
> | |
Register | |
</a> | |
</p> | |
</div> | |
<div class="form-group"> | |
Email Address | |
<input | |
required | |
type="email" | |
name="email" | |
autoComplete="username" | |
id="loginemail" | |
class="form-control" | |
/> | |
</div> | |
<div class="form-group"> | |
Password | |
<input | |
required | |
type="password" | |
name="password" | |
autoComplete="new-password" | |
minLength="8" | |
class="form-control" | |
id="loginpassword" | |
/> | |
<small class="form-text text-muted"> | |
<a | |
href="#" | |
id="forgotswitcher" | |
> | |
Forgot Password? | |
</a> | |
</small> | |
</div> | |
<div class="captcha-container form-group"></div> | |
<div class="alert alert-danger error-message form-group"></div> | |
<button | |
class="btn btn-primary btn-block btn-lg mt-4" | |
type="submit" | |
id="btn-login" | |
> | |
Sign in | |
</button> | |
<hr> | |
<button | |
type="button" | |
id="btn-google2" | |
class="btn btn-lg btn-google btn-block btn-outline"> | |
<img src="https://img.icons8.com/color/16/000000/google-logo.png" class="mr-2"> Sign in with Google | |
</button> | |
</form> | |
</div> | |
<div class="d-none" id="forgotpassword"> | |
<form onsubmit="return false;" method="post"> | |
<div> | |
<h3 class="h2">Forgot password</h3> | |
<p> | |
Back to | |
<a | |
href="#" | |
id="registerSwitcher2" | |
> | |
Log In | |
</a> | |
</p> | |
</div> | |
<div class="form-group" id="forgot-contents"> | |
Email Address | |
<input | |
required | |
type="email" | |
name="email" | |
autoFocus="true" | |
autoComplete="username" | |
id="forgotemail" | |
class="form-control" | |
/> | |
</div> | |
<div class="captcha-container form-group"></div> | |
<div class="alert alert-danger error-message form-group"></div> | |
<button | |
class="btn btn-primary btn-block btn-lg mt-4" | |
type="submit" | |
id="btn-forgot" | |
> | |
Lookup | |
</button> | |
</form> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</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.16/auth0.min.js"></script> | |
<script src="https://cdn.auth0.com/js/polyfills/1.0/object-assign.min.js"></script> | |
<script> | |
window.addEventListener('load', function() { | |
var config = JSON.parse( | |
decodeURIComponent(escape(window.atob('@@config@@'))) | |
); | |
document.getElementById('registerSwitcher').addEventListener('click', function(e){ | |
e.preventDefault(); | |
clearErrors(); | |
document.getElementById('registerform').className = 'd-none'; | |
document.getElementById('loginform').className = ''; | |
document.getElementById('forgotpassword').className = 'd-none'; | |
document.getElementById('extrainfo').className = 'd-none'; | |
}); | |
document.getElementById('registerSwitcher2').addEventListener('click', function(e){ | |
e.preventDefault(); | |
clearErrors(); | |
document.getElementById('registerform').className = 'd-none'; | |
document.getElementById('loginform').className = ''; | |
document.getElementById('forgotpassword').className = 'd-none'; | |
document.getElementById('extrainfo').className = 'd-none'; | |
}); | |
document.getElementById('loginSwitcher').addEventListener('click', function(e){ | |
e.preventDefault(); | |
clearErrors(); | |
document.getElementById('registerform').className = ''; | |
document.getElementById('loginform').className = 'd-none'; | |
document.getElementById('forgotpassword').className = 'd-none'; | |
document.getElementById('extrainfo').className = ''; | |
}); | |
document.getElementById('forgotswitcher').addEventListener('click', function(e){ | |
e.preventDefault(); | |
clearErrors(); | |
document.getElementById('registerform').className = 'd-none'; | |
document.getElementById('loginform').className = 'd-none'; | |
document.getElementById('forgotpassword').className = ''; | |
document.getElementById('extrainfo').className = 'd-none'; | |
}); | |
if(config && "internalOptions" in 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(e) { | |
e.preventDefault(); | |
clearErrors(); | |
var button = this; | |
var username = document.getElementById('loginemail').value; | |
var password = document.getElementById('loginpassword').value; | |
button.disabled = true; | |
webAuth.login({ | |
realm: databaseConnection, | |
username: username, | |
password: password, | |
captcha: captcha.getValue() | |
}, function(err) { | |
if (err) displayError(err); | |
button.disabled = false; | |
}); | |
} | |
function forgotpassword(e) { | |
e.preventDefault(); | |
clearErrors(); | |
var button = this; | |
var email = document.getElementById('forgotemail').value; | |
button.disabled = true; | |
webAuth.changePassword({ | |
connection: databaseConnection, | |
email: email, | |
captcha: captcha.getValue() | |
}, function (err, resp) { | |
if (err) { | |
if (err) displayError(err); | |
} else { | |
document.getElementById("forgot-contents").innerHTML = resp; | |
document.getElementById("btn-forgot").classList.add('d-none'); | |
button.disabled = false; | |
} | |
}); | |
} | |
function signup(e) { | |
e.preventDefault(); | |
clearErrors(); | |
var button = this; | |
var email = document.getElementById('regemail').value; | |
var password = document.getElementById('regpassword').value; | |
button.disabled = true; | |
webAuth.redirect.signupAndLogin({ | |
connection: databaseConnection, | |
email: email, | |
password: password, | |
captcha: captcha.getValue() | |
}, function(err) { | |
if(err) { | |
displayError(err); | |
} | |
else { | |
console.error('unknown error', err); | |
} | |
button.disabled = false; | |
}); | |
} | |
function loginWithGoogle() { | |
webAuth.authorize({ | |
connection: 'google-oauth2' | |
}, function(err) { | |
if (err) displayError(err); | |
}); | |
} | |
function clearErrors() { | |
var errorMessage = document.getElementsByClassName('error-message'); | |
for (var i=0; i<errorMessage.length; i++) { | |
errorMessage[i].innerHTML = ""; | |
errorMessage[i].style.display = 'none'; | |
} | |
} | |
function displayError(err) { | |
captcha.reload(); | |
var errorMessage = document.getElementsByClassName('error-message'); | |
for (var i=0; i<errorMessage.length; i++) { | |
errorMessage[i].innerHTML = err.policy || err.description; | |
errorMessage[i].style.display = 'block'; | |
} | |
} | |
document.getElementById('btn-login').addEventListener('click', login); | |
document.getElementById('btn-google').addEventListener('click', loginWithGoogle); | |
document.getElementById('btn-google2').addEventListener('click', loginWithGoogle); | |
document.getElementById('btn-signup').addEventListener('click', signup); | |
document.getElementById('btn-forgot').addEventListener('click', forgotpassword); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment