[MUSIC PLAYING] PETER FRIESE: Hi, everyone. Welcome to this "Firebase
Fundamentals" video where I'll show
you how to get up and running quickly with
Firebase Authentication in your web application. We are going to use the
new version of the Firebase JavaScript SDK and as David
mentioned in his video, version 9 of our
JavaScript SDK makes use of tree shaking to remove
all the stuff you don't need. This is particularly useful
for Firebase Authentication. You rarely want to use all of
the authentication providers in your app. So with v9, tree shaking
can remove all providers you don't need, resulting
in a much smaller download size of your app. So in this video, I'm
assuming that you've already gotten started with the
initial Firebase setup, using something like webpack
or rollup in a web application as described in David's video. If you don't know what
I'm talking about, make sure you've watched that
one first before continuing. All right, let's take a look
at the code for this project. So I've gone ahead and created
an empty starter project, pretty much what David had
at the end of his video. I have a very simple
HTML file, which contains the code
for a couple of UIs I'm going to use
to log into my app. Over here in indexJS
I have my code, which gets compiled and
bundled up with webpack. I've configured webpack
to watch my source folder. And I've also installed
HTML webpack plug-in. This will copy my index HTML
file and add a script tag to load my bundled code. I go ahead and run MPX
webpack to start webpack. Once it's finished, we can see
the result in the dist folder. And then in a new
shell, I'll run Firebase serve --only
hosting to serve the contents of the dist
folder on my local machine. Once the local server
is up and running, it will show a message
saying that it runs on port 5,000 on local host. I can then Command
click on the link to open it in my browser
and voila, there is my page. To check everything is
working as expected, let me make a small change
to index HTML and hit Save. In the webpack
output, we can see that it's bundling
my project, so let me hit Refresh in the
browser to reload the page. OK, let's get coding. First, let's go to
indexJS and take a look at what we've got so far. At the top of the file, I've
got the imports for my CSS files and some UI elements from this
other JavaScript file UI.JS. This mostly contains code to
connect to the UI elements of my little application. To keep things simple, I'm
not using any framework. This is all just plain
JavaScript and straight up dom coding. Next, I import initialize
app and call this function to initialize Firebase using
this configuration object. Now, if you remember what
David said in his video, instead of using a
namespace-based approach, in v9 of the Firebase
SDK for JavaScript, we use a functional approach. So what this means is that you
need to hold on to the Firebase instance and pass it
to the initialization function of the Firebase
service you want to use. The functions of all
the Firebase services follow the same approach. Their first parameter
requires a reference to the service they operate on. So you need to hold onto
that service reference and pass it into any
Firebase function you call. You can think of it
a bit like a chain. You pass the result of one
call into the next call. Before you can
use Firebase Auth, you need to import
and initialize it. To use any of
Firebase's services, you call the function
that is named get and then the name of
the Firebase service you want to use. So getAuth for Firebase Auth,
getFirestore for Firestore, and so on. And the name of the
module to import from follows the same naming scheme. So let me add the import
for getAuth up here. And while I'm at it, I'm going
to import connectAuthEmulator and signInWithEmailAndPassword
as well because these will be the functions
I'm going to use later. Next, I can initialize Firebase
Auth by calling getAuth and pass in the
Firebase app instance. I'll keep the auth
instance around, since I'm going to need
it a couple of times. The first thing I want to do
after initializing Firebase Auth is to connect my app to
the Firebase Emulator Suite. You can think of
the Emulator Suite as kind of your own personal
test instance of Firebase, running locally on your machine. And it's perfect for
development and testing as all calls happen locally. So it is super fast. Also, and this is one
thing I personally find really
reassuring, you don't need to worry about messing
up your production data. Right, so to connect Firebase
Auth to the emulator, all I have to do is
call connectAuthEmulator and provide a reference to
the auth instance and the URL I want the emulator to run on. By default, this will be
port 9099 on local host. And with that, we're now
ready to sign the user in. For this video, I'm going
to use email and password authentication, since it
is super easy to set up. However, please bear
in mind that coming up with a strong password
is challenging and most people are
not very good at this. But not to worry, Firebase
Auth supports a bunch of other authentication
providers that are even more
convenient for users, such as email and link
authentication, Google Sign-In, Sign in with Apple, and more. And we will be looking
at them in later episodes of the series. I'm first going to
create a function that I can call when the user
taps on the Login button. I'm going to call it
loginEmailPassword. And now I can hook it
up to the click event listener of the Login
button on the login form. To sign the user in, I need
to fetch their credentials by reading the value of the
email and password input fields of the login form. And now I've got
everything in place to call the
signInWithEmailAndPassword function. This function takes three
parameters, the Firebase Auth instance, the email
address, and the password. The return value of the
function is a promise, so I can use await to call
it and then assign the return value to a new local variable. When calling in a sync
function using await, the promise will be unwrapped. So this variable is of
type user credential. User credential has three
attributes, and one of them is the user itself, so let's
log this out to the console. Great, let's now run this. In the background, webpack
has bundled up the code. And I've got Firebase
hosting running locally to serve up my app on
port 5000, So I can just switch over to my browser
and hit Refresh to run the latest version of my app. So let me try logging in
as Me@AwesomeKittens.Test with a password of Test1234. But when I tap the Login
button, the browser console shows an error. Error, connection refused. Why is that? So if you remember,
right at the beginning, after I set up Firebase Auth,
I called connectAuthEmulator and instructed it to connect
to port 9099 on local host. But I didn't start the emulator. And this is why we get
this error message. It's an easy mistake to
make, but it's easy to fix. So let me start the
emulator by running Firebase emulators:start --onlyAuth
from the project folder. This will run just the Firebase
authentication emulator. And now my app should be able
to communicate with the Emulator Suite. Let me try logging in
with the same credentials. And now when I tap on the Login
button, I get another error. This time it's Auth,
user not found. And that is because my
Firebase project doesn't have a user with that email address. So one way to fix this is to
create a new account using the Firebase console. Here in the console for
the Firebase Auth emulator, I can see that there aren't
any uses for this project yet. So I'll check the
Add User button to open a dialogue
that lets me enter the details for a
new user account, such as their display
name, a photo URL, and a bunch of other options. So let me fill in the
email and password fields. Me@AwesomeKittens.Test
and Test1234. One thing to note is
that I don't actually own this email address. The test top level domain
is just for testing, so this email is unverified. If you're considering using
email and password sign in, you should definitely implement
an email verification flow to make sure users actually
own the email address they provided. You can use the default
verification flow from your client or
you can customize it using the Admin SDK. Another option is to use email
and link authentication or one of the OAuth2 providers
Firebase supports. OK, once I create
the user account, I can see the user and the
console along with their UID. The UID is a user ID that
Firebase assigns to the user. This ID is guaranteed
to be unique, no matter how they sign in. So now that I've
created a user account, I can try signing in again. And since I used console.log
to print the user details onto the console, I
can now see the user details. For example, here is their email
address and there is the UID. If I don't provide the correct
password when signing in, Firebase Auth will return
an error of wrong password. So before I show you how to
create a new user account using code, let me display
this error on the UI to make this a better
user experience. To do this, I'm going
to wrap the call to sign in with email and
password in a try catch block. And then inside the
catch block, I'll print the error to the console. I'll also send it to the
showLoginError function that I defined in Ui.JS. This function will
check if the error code equals to
AuthErrorCodes.invalidpassword and will return a human
readable error message. Let me quickly show what this
looks like in the browser. So when I try signing in
with the wrong password, I will now get an error message. That's so much
more user friendly than displaying the
error in the console. OK, so I created a user account
using the Firebase console. But in a real
application, you will want to allow users
to sign up themselves. So let me show you how to create
a new user account using code. I first create an empty
function and name, create account, and
hook it up to the click handler of the Sign Up button. To create a new
user account, I can use the
createUserWithEmailAndPassword function. Let me first impart
this function up here. Now, the
createUserWithEmailAndPassword function has the same parameters
as signInWithEmailAndPassword. So I can go ahead
and copy the code I wrote for the
Login button and then paste it into the
create account function. Now, back down in
create account, I can replace this call with
createUserWithEmailAndPassword. Note how the code
completion, however, shows me the documentation
for this function. And sure enough, I can
see that it does indeed expect the same three parameters
of email and password. I'd also like to call out that
this function will not only create the user
account, but will also log in that particular user,
which is exactly what I want in this case. Perfect, so I'll
take this one then. And now let's see
this in action. This time, I'll enter an email
that is not yet in the system. You@AwesomeKittens.Test. And a password, [HUMMING]. And when I tap the
Sign Up button, I can see that I'm no sign
in as You@AwesomeKittens.Test over here in the console. However, the UI doesn't
reflect that I'm signed in. So the user doesn't
get any feedback, which is a pretty terrible UX. So in the next
step, I'll show you how to update the UI according
to the authentication state. To update the UI according
to the authentication state, we can make use of the
onAuthStateChange listener. This method allows
us to register a closure that will be called
whenever the authentication state changes. For example, when the user
signs in, or logs out. The first thing is to add
onAuthStateChange to the list of imports. Now let me create a
function that I can call as soon as the UI is loaded. I'll call it monitorAuthState. Inside, I'm going to call
onAuthStateChanged, which takes the closure
that will receive two parameters, the auth
object and a user instance. The user parameter can either
contain a JavaScript object, which represents the
currently signed in user or 0, which means the
user has signed out. So if the user has signed in,
I want to hide the login form and show the application
window instead. And if the user is 0, which
means they are signed out, I want to show the login form
and hide the application window instead. And now when I
refresh the browser, the application window
is hidden and I can only see the login form. When I sign in using
one of the accounts I created earlier, the
login form disappears and the application window
appears instead, showing me some details about the user. Perfect, we're almost done. Finally, let's take a
look at how to log out. Logging out is probably
the simplest function call in Firebase Auth. Again, let me impart
the function first and then implement
a simple function and connect it to
a Logout button. Like all other Firebase
Auth functions, signOut is an async
function, which is why we call it using await. And now, back in the browser, I
can log out of the application. And thanks to the
authentication state listener I implemented earlier,
the UI updates automatically and displays the
login form again. And with this, we're at the
end of this quick introduction to Firebase Authentication
on the web using v9 of the Firebase JavaScript SDK. A couple of things to keep
in mind before I let you go. One, keep in mind that picking a
strong password is challenging, so consider using an
authentication mechanism that doesn't require your users
to deal with passwords at all. For example, email and
link authentication works great, doesn't
use any passwords, and has the added benefit of
verifying the user's email address as part of
the sign up flow. Two, use the Firebase
Emulator Suite to develop locally and speed
up your development cycles, as you saw in this video
it's easy to connect your project to the emulators. Literally just one
line of code, and you don't have to worry about
messing up your production data by accident. And finally, check out all the
other authentication providers such as Google Sign-In, Facebook
Login, or Sign in with Apple. What's really cool about them
is that users who are already using one of these
providers can sign in to your app
with just one tap. It really doesn't get
any easier than that. Thanks for watching,
and we'll see you soon on another episode of
"Firebase Fundamentals." [MUSIC PLAYING]