Skip to content

Instantly share code, notes, and snippets.

@tunnela
Last active February 3, 2025 12:36
Show Gist options
  • Save tunnela/6e4ee5f1d72a50e89d8be99fca1158f5 to your computer and use it in GitHub Desktop.
Save tunnela/6e4ee5f1d72a50e89d8be99fca1158f5 to your computer and use it in GitHub Desktop.
Webflow + Firebase user authentication

Webflow + Firebase user authentication

You can find a demo at https://webflow-authentication.webflow.io/sign-up.

1. Set up Firebase authentication

Log in to Firebase console. Create a new app and from the left side menu, under Develop, navigate to Authentication. Enable Email/Password sign-in provider. After this, create a Web application under the current Firebase project and copy the given firebaseConfig object.

2. Create Webflow pages

Go to the project settings and Custom Code tab. Add content from webflow-custom-code-before-body.html gist file to Footer Code input. Replace webflowAuth.firebaseConfig with the one you copied in the previous step. After this go to designer and create 3 new pages:

  1. /user page which is meant for logged in users.
  2. /log-in page which is used for logging in.
  3. /sign-up page which is used for signing up.

On /sign-up page, create a form and inside it add a submit button plus two input fields - email and password. Then do the following adjustments:

  1. Give form element (form element inside form, Form > Form) custom data attribute called data-signup-form.
  2. Give email field custom data attribute called data-signup-email.
  3. Give password field custom data attribute called data-signup-password.
  4. Give form error element custom data attribute called data-signup-error.
  5. Add custom data attribute called data-user-unauth to the body element.

On /log-in page, create a form and inside it add a submit button plus two input fields - email and password. Then do the following adjustments:

  1. Give form element (form element inside form, Form > Form) custom data attribute called data-login-form.
  2. Give email field custom data attribute called data-login-email.
  3. Give password field custom data attribute called data-login-password.
  4. Give form error element custom data attribute called data-login-error.
  5. Add custom data attribute called data-user-unauth to the body element.

On /user page add custom data attribute called data-user-auth to the body element. In addition to this, you can show any user properties returned from Firebase by giving an element custom data attribute called data-user. After this you can use user properties with curly bracets i.e. Your email is {{email}}.

If you have a navigation element from which you can navigate to /log-in, /sign-up etc. pages, you can adjust their visibility by using custom data attributes called data-user-auth and data-user-unauth. You can also add either one of those data attributes to body element which will adjust visibility of the given page. Log out button can be created by giving a link element a custom data attribute called data-logout.

3. Credits

Some of the ideas are taken from the YouTube video series by Jason Dark which you can find at https://www.youtube.com/watch?v=30AIpEnsEaQ&list=PL4TuDUnZkkhzSwfbFj6EJjxim6218ORc0.

<script src="https://www.gstatic.com/firebasejs/8.1.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.1.1/firebase-analytics.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.1.1/firebase-auth.js"></script>
<script>
var webflowAuth = {
loginPath: '/log-in',
loginRedirectPath: '/user',
signupPath: '/sign-up',
signupRedirectPath: '/user',
logoutRedirectPath: '/',
firebaseConfig: {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
}
};
</script>
<!-- you can replace this with the content from webflow-firebase-user-authentication.js -->
<script src="webflow-firebase-user-authentication.js"></script>
/*
Example config
var webflowAuth = {
loginPath: '/log-in',
loginRedirectPath: '/user',
signupPath: '/sign-up',
signupRedirectPath: '/user',
logoutRedirectPath: '/',
firebaseConfig: {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
}
};
*/
firebase.initializeApp(webflowAuth.firebaseConfig);
firebase.analytics && firebase.analytics();
{
var user;
var bodyAuth = document.body.getAttribute('data-user-auth');
var bodyUnauth = document.body.getAttribute('data-user-unauth');
var userAuth = document.querySelectorAll('[data-user-auth]');
var userUnauth = document.querySelectorAll('[data-user-unauth]');
var userDisplayName = document.querySelectorAll('[data-user-displayName]');
var userEmail = document.querySelectorAll('[data-user-email]');
var userContent = document.querySelectorAll('[data-user]');
userAuth.forEach(function(el) { el.style.display = 'none'; });
userUnauth.forEach(function(el) { el.style.display = 'none'; });
function updateContent() {
if (!user) {
return;
}
userContent.forEach(function(el) {
el.innerText = el.innerText.replace(/\{\{([^\}]+)\}\}/g, function(match, variable) {
return typeof user[variable] === 'undefined' ? '' : user[variable];
});
});
}
firebase.auth().onAuthStateChanged(function(authUser) {
user = authUser;
updateContent();
if (user && bodyUnauth) {
window.location.href = webflowAuth.loginRedirectPath;
} else if (!user && bodyAuth) {
window.location.href = webflowAuth.loginPath;
}
if (user) {
userAuth.forEach(function(el) { el.style.display = null; });
userUnauth.forEach(function(el) { el.style.display = 'none'; });
userEmail.forEach(function(el) { el.innerText = user.email; });
userDisplayName.forEach(function(el) { el.innerText = user.displayName; });
} else {
userAuth.forEach(function(el) { el.style.display = 'none'; });
userUnauth.forEach(function(el) { el.style.display = null; });
userEmail.forEach(function(el) { el.innerText = ''; });
userDisplayName.forEach(function(el) { el.innerText = ''; });
}
});
var signupForms = document.querySelectorAll('[data-signup-form]');
var signupErrors = document.querySelectorAll('[data-signup-error]');
var signupLoading = document.querySelectorAll('[data-signup-loading]');
var signupIdle = document.querySelectorAll('[data-signup-idle]');
signupForms.forEach(function(el) {
var signupEmail = el.querySelector('[data-signup-email]');
var signupPassword = el.querySelector('[data-signup-password]');
el.addEventListener('submit', function(e) {
e.preventDefault();
e.stopPropagation();
signupErrors.forEach(function(el) { el.style.display = 'none'; });
signupLoading.forEach(function(el) { el.style.display = 'block'; });
signupIdle.forEach(function(el) { el.style.display = 'none'; });
firebase.auth().createUserWithEmailAndPassword(signupEmail.value, signupPassword.value)
.then(function(authUser) {
user = authUser;
window.location.href = webflowAuth.signupRedirectPath;
})
.catch(function(error) {
signupErrors.forEach(function(el) {
el.innerText = error.message;
el.style.display = 'block';
});
setTimeout(function() {
signupLoading.forEach(function(el) { el.style.display = 'none'; });
signupIdle.forEach(function(el) { el.style.display = null; });
}, 1000);
});
});
});
var loginForms = document.querySelectorAll('[data-login-form]');
var loginErrors = document.querySelectorAll('[data-login-error]');
var loginLoading = document.querySelectorAll('[data-login-loading]');
var loginIdle = document.querySelectorAll('[data-login-idle]');
loginForms.forEach(function(el) {
var loginEmail = el.querySelector('[data-login-email]');
var loginPassword = el.querySelector('[data-login-password]');
el.addEventListener('submit', function(e) {
e.preventDefault();
e.stopPropagation();
loginErrors.forEach(function(el) { el.style.display = 'none'; });
loginIdle.forEach(function(el) { el.style.display = 'none'; });
loginLoading.forEach(function(el) { el.style.display = 'block'; });
firebase.auth().signInWithEmailAndPassword(loginEmail.value, loginPassword.value)
.then(function(authUser) {
user = authUser;
window.location.href = webflowAuth.loginRedirectPath;
})
.catch(function(error) {
loginErrors.forEach(function(el) {
el.innerText = error.message;
el.style.display = 'block';
});
setTimeout(function() {
loginIdle.forEach(function(el) { el.style.display = null; });
loginLoading.forEach(function(el) { el.style.display = 'none'; });
}, 1000);
});
});
});
var authLogout = document.querySelectorAll('[data-logout]');
authLogout.forEach(function(el) {
el.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
firebase.auth().signOut().then(function() {
user = null;
window.location.href = webflowAuth.logoutRedirectPath;
})
.catch(function() {});
});
})
}
@maria-arce
Copy link

Hello tunnela, thank you for this integration works well. I have a question, I'm trying to also integrate realtime database so I added first the database script call at the top, after the firebase-auth.js and then the database URL into the firebaseConfig area + script to load to get the snapshot to the database. When I published it I get an error "provider.ts:108 Uncaught TypeError: Cannot read property 'instanceIdentifier' of undefined". I recreated just my call to the realtime database in a html file and it worked in the console without error. Do I'm missing something? :) I also noticed this part "firebase.analytics && firebase.analytics();" I need to initialize similar my database? Thank you in advance for read me

@tunnela
Copy link
Author

tunnela commented Jun 8, 2021

That's great to hear @maria-arce!

It's a long time since I worked on this project but there is actually a v2 of this demo (WIP) where I've implemented Firestore. You can find it at:
https://webflow-authentication-v2.webflow.io

Sign up to see how it works and view the source of the page to see the code. I hope this helps!

@maria-arce
Copy link

Hello @tunnela, thank you very much! will take a look :)

@shanedolley
Copy link

Freakin awesome. Thanks so much @tunnela !!!

@samsrose
Copy link

Awesome! Thanks a lot!

@osamaaliarshad
Copy link

Hey thank you very much for this tutorial! Everything works smoothly as expected :). Would it be possible for you to briefly explain how one could go about adding a forgot password button? Thanks again this is great help.

@osamaaliarshad
Copy link

Scratch that last message, I figured it out!

For anyone else who wants to add a forgot password button, it's very similar to the other methods already outlined by tunnela. So add something like this to your code:

  var forgotPasswordForm = document.querySelectorAll('[data-forgot-form]');
  var forgotErrors = document.querySelectorAll('[data-forgot-error]');
  var forgotLoading = document.querySelectorAll('[data-forgot-loading]');
  var forgotIdle = document.querySelectorAll('[data-forgot-idle]');

  forgotPasswordForm.forEach(function(el){
    var loginEmail = el.querySelector('[data-forgot-email]');

    el.addEventListener('submit', function(e) {
      e.preventDefault();
      e.stopPropagation();

      forgotErrors.forEach(function(el) { el.style.display = 'none'; });
      forgotIdle.forEach(function(el) { el.style.display = 'none'; });
      forgotLoading.forEach(function(el) { el.style.display = 'block'; });

      firebase.auth().sendPasswordResetEmail(loginEmail.value).then(function(authUser) {
        user = authUser;
        window.location.href = webflowAuth.loginRedirectPath;
      }).catch(function(error) {
          forgotErrors.forEach(function(el) {
            el.innerText = error.message;
            el.style.display = 'block';
          });
          setTimeout(function() {
            forgotIdle.forEach(function(el) { el.style.display = null; });
            forgotLoading.forEach(function(el) { el.style.display = 'none'; });
          }, 1000);
      });
    });
  });

@tunnela
Copy link
Author

tunnela commented Jan 7, 2022

@osamaaliarshad great to hear that you were able to figure it out by yourself. Oh and thanks for sharing it with everyone! 💪

@tunnela
Copy link
Author

tunnela commented Jan 7, 2022

You're welcome @shanedolley @samsrose !

@osamaaliarshad
Copy link

Any chance anyone knows how to add email verification so that the user is emailed to confirm their email address before being fully authenticated ?

I've identified that the firebase command for this is something like
user.sendEmailVerification()

But for the life of me I can't quite get it to work haha

@osamaaliarshad
Copy link

NEVERMIND figured it out again lol

Under the onAuthStateChanged add something like this:
document.getElementById("btnVerifyEmail").addEventListener('click', function (event) { user.sendEmailVerification() .then(function () { document.getElementById("btnVerifyEmail").style.display = "none"; console.log("Sent verification email") }) .catch(function (error) { console.log("Oops! There was an error sending verification email.") }); })

@bossdown123
Copy link

anyone know how to use firestore to display specific user data

@tuckeralford
Copy link

@tunnela I'm stuck on adding the custom attributes in Webflow. It looks lik I have everything configured correctly in the frontend, but nothing is functioning. Any help would be sweet!

Screen Shot 2022-02-10 at 4 28 11 PM

Thanks so much!

@tunnela
Copy link
Author

tunnela commented Feb 11, 2022

@bossdown123 you can checkout my WIP example at https://webflow-authentication-v2.webflow.io where I use Firestore to save user information!

@tunnela
Copy link
Author

tunnela commented Feb 11, 2022

@tuckeralford I can't help much without seeing the website and its HTML/JS source code.

@truereflectionmedia
Copy link

It works great thank you for this. One part I'm not clear on why use Forms and forEach instead of a single form. I'm using this with a popup form. just curious.

@arnotventures
Copy link

I noticed all of the API information is exposed.. is that an issue?

@truereflectionmedia
Copy link

Arno the API is designed that way, you lock it down in google console. Also within firebase if using the firestore you create security rules.

@biniam-ux
Copy link

Thanks @tunnela for the post. I've managed to create gated access using firebase auth!
also thanks to @osamaaliarshad for the 'forgot password" part, that waas great too!

my little contribution will be a "delete user" functionality, that allow user to delete their account from firebase when logged in (if anyone need it):

var deleteAccountButton = document.querySelector("#delete-account-button"); deleteAccountButton.addEventListener("click", function () { firebase .auth() .currentUser.delete() .then(function () { // User deleted. }) .catch(function (error) { // An error occurred. }); });

btw, does anyone know as way to send user data (such as name, surname) to firebase firestore database for each individual user? that will be dope!

@Opsje
Copy link

Opsje commented Jun 15, 2023

Has anyone been able to get it working with firebase version 9?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment