Learn how to collect custom data from users in multiple steps with Firebase email password auth https://angularfirebase.com/lessons/multi-step-signup-firebase-email-password-auth-angular-reactive-forms/

- Firebase Auth: https://firebase.google.com/docs/auth/web/password-auth
- Angular 5: https://angular.io/guide/reactive-forms
2024-02-04T07:55:48.660Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
e3b9cfb0-3fbd-4cfe-aec7-d15470e3edfe
604ccddd3388443cdbac74b1d1b486c92b06592a71bdf7ed3bd4bab0f0b21bfb
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
Firebase makes basic user authentication very easy, but what happens if you require additional data from your user before they're authorized to start using your app.
In this episode, I'm going to set up a multi step sign up form that requires the user to fill out a catchphrase on their user profile before they're authorized to start using the app.
App.
Then we're going to secure all the application data on both the front end and the back end.
This feature works by setting up a custom user document in the Firestore database.
We can then verify that the current user has the correct information on their document before they're authorized to perform certain actions.
In order to build this feature, app.
I'm going to be using the Firestarter demo app, which is on GitHub.
You can clone it if you want, but this code can be applied to any Angular app that's using Firebase.
App.
Before we get started, make sure to subscribe, and you can find all the source code at angularfirebase.com.
The first place we're going to start is in the auth service, app.
And in my case, it's in the core module.
The goal of the service is to keep track of the current user and give them the ability to sign in via email and password.
App.
The important imports to take note of here are AngularFire auth and AngularFirestore as well as the switch map operator from RxJS.
App.
The first thing I'm going to do is set up an interface to model our user data.
We need to have a user ID and email address, which we'll get from Firebase auth, and then our custom piece of data is the catchphrase.
Notice that you don't need to actually add the password to the user interface.
That's all handled by AngularFire auth.
App.
So our actual user is going to be an observable type to this interface, then we'll inject our dependencies in the constructor.
The notify service that I'm adding here is part of the demo app.
App.
It's not required, but it's used to show the end user any problems with the sign in process.
Then inside the constructor, we'll define the user variable.
App.
So we do this by calling AngularFireAuthState, which gives us an observable that we can call switch map on.
If the current user is logged in, app.
Then we'll go ahead and retrieve the user data from Firestore.
We do that by calling a f s doc and then point to that current user's user ID app and then call value changes to get the observable.
If the user is not logged in, then we're just going to return an observable of null.
App.
That chunk of code is going to keep track of the current user at the global level throughout our application.
It's easy for things to go wrong with email password auth.
For example, the user might try to log in end with an email address that's already been taken.
When that happens, we're going to use this helper method to notify the user in the front end.
After that, We're going to create another helper method that will create a new user document when the user first signs up.
When the user signs up, Firebase will give us a user object.
App.
We can then use that object to point to a document in Firestore.
At this point, we're only gonna have the user's email address and user ID, so we'll go ahead and set that to an object.
App.
Then we can update the document in Firestore.
Now we need a way to create a new user by having them log in with an email address and a password.
App.
So we'll create a method that will handle this data and then we can call AngularFire auth create user with email and password.
App.
This is going to return a Promise and if it's successful, it will return the user object.
And then we'll go ahead and use that user object app to create the user document in that helper method that we just defined.
And lastly, we'll catch any errors and notify the user if there's any problem with the sign up.
App.
That handles the first part of the sign up, but if you have additional steps, you'll need a method to update data on that user document.
App.
This method will take the current user as well as the data that we wanna update, and then we'll point to that user's user ID in Firestore and update the data.
App.
Now let's jump over to the user form component and put the service to use.
1st, I wanna show you how it's set up in the router.
So here I'm in the app routing module, app.
And I have 3 unrelated components that we're going to lock down for unauthorized users later.
And then our user form component, we're going to load at the login path.
App.
We're going to come back here a little bit later to add a router guard to secure all of these routes.
Then you'll also need to go into whichever NG module uses this component app and import the Reactive Forms module from Angular forms.
Now we can start writing this component.
First, we need the auth service, app.
And we also need a few reactive forms pieces, including form group, form builder, and validators.
The component is going to use 2 separate form groups.
App.
So the first form will be the sign up form, and the second form will be the detail form where we collect any additional information we want from the user.
In this case, we're only collecting the catchphrase property, but you could collect any information you want there.
Then we'll inject Form Builder in the constructor as well as the auth service.
App.
To create a reactive form, you call form builder group, and then you pass it an object where each key is a corresponding form field.
So in this case, we have an email input.
Then app.
Then we set its value equal to an array where the first value in that array is an empty string, and then the second value is another array of validators.
App.
These validators are based on their HTML counterparts.
In this case, we are going to validate the email as required and that it has an email format.
App.
For the password, we're going to use a regular expression, which just validates that there's at least one number present in the password string.
And And then we're also gonna validate that it has a minimum length of 6 and a max length of 25.
Then we'll set up the second form in exactly the same way, but it's actually much assembler.
We'll just say detail form is the Form Builder group, and its only field is going to be the catch phrase, which is required.
App.
And that's all it takes to set up a reactive form.
It's just a series of form fields that are defined directly in your TypeScript.
The main problem is that they generally create a lot of TypeScript code.
So we can cut down on this code at least a little bit by using getters.
So we'll call sign up form get email, app.
And we'll repeat this pattern for each individual form field.
When we get to the actual form HTML, you'll see that this drastically cuts down on the amount of code that we need to use in the template.
The last thing we need is an event handler for when these forms are submitted.
So when they submit the sign form, we'll call our email sign up method from the service with their email value and password value.
And for the catch phrase, we simply call the auth service update user method with the catch phrase that they enter into that form.
Now we're going to switch over to the HTML, and I'll show you how to use this reactive form in the template.
App.
I'm going to set up an NG container that's going to wrap both of the forms.
The reason for this is that we can unwrap the user observable to apply some conditional logic to determine which form to show.
So we'll do that by calling auth user async or we're going to show an empty object if the user is null.
And then we're gonna set that to the user template variable.
App.
I realize that looks kind of weird, but it is a very useful technique in Angular.
The next thing we'll do is set up our form group.
App.
So we do that by calling form group with our sign up form.
This form should only be shown if we don't have a user ID, meaning the user has no Firebase account at all.
App.
Then I'm going to add the detail form right below it, and we're only gonna show this form if the user is authenticated, but they still don't have the catch phrase on their user document.
App.
Then I'll set up one more block here, and this one will show if the user is logged in and they have a catch phrase, meaning the form is 100% complete.
App.
You could extract this into separate components, but I'm just showing it all in one go here just to keep this as simple as possible.
Going back to the sign up form, we'll app.
First, find our sign up method to the NG submit event.
Then we'll set a label and a form input for the email address.
App.
We connect this input to our reactive form in the TypeScript by calling form control name followed by email.
Because we set validators on this form, we can determine whether or app.
It is in a valid state based on the user's input.
When the form is not valid, we want to show an error message, and we only wanna show it if the form is dirty, app, which means that the user has started typing into that Form Input.
Then we'll go and do the same exact thing for the password, but the only difference instead of dirty here, I'm going to use touched.
Action.
The form input is considered touched when the user has entered their mouse inside of that form input.
So that just gives you another option for determining when you want to actually display the error message.
App.
We can also tell when a form is valid.
By calling sign up form valid, we can determine if the entire form is valid as well as all of the inputs contained inside of it.
App.
As a final touch, we'll disable the submit button so the user can't accidentally submit an invalid form.
When the user submits their form and they're successfully authenticated, app.
It's going to hide this initial form and then bring up our secondary form here.
So for this one, we'll bind it to the set catchphrase method app.
And then we'll go ahead and add the FormControl name and then another submit button for that as well.
The end result looks something like this.
App.
We start typing in the form and then we get this validation error until we actually enter a valid email then it has the green border.
App.
Then we go ahead and enter our password and we get the green message that the form looks good.
So now we authenticate in Firebase and then it brings up the secondary form.
App.
The sign up process works as expected at this point, but we still want to set up a router guard to prevent our users from navigating away from the form if they haven't fully completed it.
App.
We can do that by setting up an auth guard that we'll use in our app routing module.
Guards use the injectable decorator, so they behave just like services do in Angular.
App.
First, I'm going to import it into the module and then add it to the provider's array.
Then you can use the guard on individual routes by setting the can activate property, and you just pass it to its array of guards.
Now we can go into the actual auth guard file, app.
And we're going to import our auth service.
And if you remember from earlier, our auth service provides a user observable.
So what we're going to do is convert app.
That user observable into a boolean that's going to determine whether or not a user is authorized to visit a certain route.
App.
So we're going to inject the auth service in the constructor, and then we're going to use the Angular router as well as that notification service that I was talking about earlier.
App.
The CanActivate method inside the guard needs to return a Boolean Observable.
So we first take our User Observable and then we map it down to a Boolean, app.
And we determine this Boolean by whether or not the user has that catch phrase property on their user document.
We convert the property to a Boolean by adding a double bang in front of it.
App.
If this evaluates to false, we're going to use the router as well as the notification service to redirect the user back to the form and then show them an error message.
App.
The end result is that any routes that have this guard applied to it will not be activated unless the user has that catch phrase property on their document in Firestore.
App.
That's only going to secure routes on the front end.
If you have truly sensitive information there, you'll want to also send a back end database rule.
App.
In this case, you can check if the catch phrase exists on the current user's document by pointing to the user document with the request auth UID.
ID.
If it's not there, the user won't be able to read or write any documents associated with this rule.
That's it app.
For multistep authentication with Firebase, if this video helped you, please like and subscribe.
And if you wanna learn more, consider becoming a pro member at angularfirebase.com.
You You'll get a free copy of my book as well as 1 on 1 project support.
Thanks for watching, and I'll see you soon.
App.

Speaker 0: Firebase makes basic user authentication very easy, but what happens if you require additional data from your user before they're authorized to start using your app. In this episode, I'm going to set up a multi step sign up form that requires the user to fill out a catchphrase on their user profile before they're authorized to start using the app. App. Then we're going to secure all the application data on both the front end and the back end. This feature works by setting up a custom user document in the Firestore database.

We can then verify that the current user has the correct information on their document before they're authorized to perform certain actions. In order to build this feature, app. I'm going to be using the Firestarter demo app, which is on GitHub. You can clone it if you want, but this code can be applied to any Angular app that's using Firebase. App.

Before we get started, make sure to subscribe, and you can find all the source code at angularfirebase.com. The first place we're going to start is in the auth service, app. And in my case, it's in the core module. The goal of the service is to keep track of the current user and give them the ability to sign in via email and password. App.

The important imports to take note of here are AngularFire auth and AngularFirestore as well as the switch map operator from RxJS. App. The first thing I'm going to do is set up an interface to model our user data. We need to have a user ID and email address, which we'll get from Firebase auth, and then our custom piece of data is the catchphrase. Notice that you don't need to actually add the password to the user interface.

That's all handled by AngularFire auth. App. So our actual user is going to be an observable type to this interface, then we'll inject our dependencies in the constructor. The notify service that I'm adding here is part of the demo app. App.

It's not required, but it's used to show the end user any problems with the sign in process. Then inside the constructor, we'll define the user variable. App. So we do this by calling AngularFireAuthState, which gives us an observable that we can call switch map on. If the current user is logged in, app.

Then we'll go ahead and retrieve the user data from Firestore. We do that by calling a f s doc and then point to that current user's user ID app and then call value changes to get the observable. If the user is not logged in, then we're just going to return an observable of null. App. That chunk of code is going to keep track of the current user at the global level throughout our application.

It's easy for things to go wrong with email password auth. For example, the user might try to log in end with an email address that's already been taken. When that happens, we're going to use this helper method to notify the user in the front end. After that, We're going to create another helper method that will create a new user document when the user first signs up. When the user signs up, Firebase will give us a user object.

App. We can then use that object to point to a document in Firestore. At this point, we're only gonna have the user's email address and user ID, so we'll go ahead and set that to an object. App. Then we can update the document in Firestore.

Now we need a way to create a new user by having them log in with an email address and a password. App. So we'll create a method that will handle this data and then we can call AngularFire auth create user with email and password. App. This is going to return a Promise and if it's successful, it will return the user object.

And then we'll go ahead and use that user object app to create the user document in that helper method that we just defined. And lastly, we'll catch any errors and notify the user if there's any problem with the sign up. App. That handles the first part of the sign up, but if you have additional steps, you'll need a method to update data on that user document. App.

This method will take the current user as well as the data that we wanna update, and then we'll point to that user's user ID in Firestore and update the data. App. Now let's jump over to the user form component and put the service to use. 1st, I wanna show you how it's set up in the router. So here I'm in the app routing module, app.

And I have 3 unrelated components that we're going to lock down for unauthorized users later. And then our user form component, we're going to load at the login path. App. We're going to come back here a little bit later to add a router guard to secure all of these routes. Then you'll also need to go into whichever NG module uses this component app and import the Reactive Forms module from Angular forms.

Now we can start writing this component. First, we need the auth service, app. And we also need a few reactive forms pieces, including form group, form builder, and validators. The component is going to use 2 separate form groups. App.

So the first form will be the sign up form, and the second form will be the detail form where we collect any additional information we want from the user. In this case, we're only collecting the catchphrase property, but you could collect any information you want there. Then we'll inject Form Builder in the constructor as well as the auth service. App. To create a reactive form, you call form builder group, and then you pass it an object where each key is a corresponding form field.

So in this case, we have an email input. Then app. Then we set its value equal to an array where the first value in that array is an empty string, and then the second value is another array of validators. App. These validators are based on their HTML counterparts.

In this case, we are going to validate the email as required and that it has an email format. App. For the password, we're going to use a regular expression, which just validates that there's at least one number present in the password string. And And then we're also gonna validate that it has a minimum length of 6 and a max length of 25. Then we'll set up the second form in exactly the same way, but it's actually much assembler.

We'll just say detail form is the Form Builder group, and its only field is going to be the catch phrase, which is required. App. And that's all it takes to set up a reactive form. It's just a series of form fields that are defined directly in your TypeScript. The main problem is that they generally create a lot of TypeScript code.

So we can cut down on this code at least a little bit by using getters. So we'll call sign up form get email, app. And we'll repeat this pattern for each individual form field. When we get to the actual form HTML, you'll see that this drastically cuts down on the amount of code that we need to use in the template. The last thing we need is an event handler for when these forms are submitted.

So when they submit the sign form, we'll call our email sign up method from the service with their email value and password value. And for the catch phrase, we simply call the auth service update user method with the catch phrase that they enter into that form. Now we're going to switch over to the HTML, and I'll show you how to use this reactive form in the template. App. I'm going to set up an NG container that's going to wrap both of the forms.

The reason for this is that we can unwrap the user observable to apply some conditional logic to determine which form to show. So we'll do that by calling auth user async or we're going to show an empty object if the user is null. And then we're gonna set that to the user template variable. App. I realize that looks kind of weird, but it is a very useful technique in Angular.

The next thing we'll do is set up our form group. App. So we do that by calling form group with our sign up form. This form should only be shown if we don't have a user ID, meaning the user has no Firebase account at all. App.

Then I'm going to add the detail form right below it, and we're only gonna show this form if the user is authenticated, but they still don't have the catch phrase on their user document. App. Then I'll set up one more block here, and this one will show if the user is logged in and they have a catch phrase, meaning the form is 100% complete. App. You could extract this into separate components, but I'm just showing it all in one go here just to keep this as simple as possible.

Going back to the sign up form, we'll app. First, find our sign up method to the NG submit event. Then we'll set a label and a form input for the email address. App. We connect this input to our reactive form in the TypeScript by calling form control name followed by email.

Because we set validators on this form, we can determine whether or app. It is in a valid state based on the user's input. When the form is not valid, we want to show an error message, and we only wanna show it if the form is dirty, app, which means that the user has started typing into that Form Input. Then we'll go and do the same exact thing for the password, but the only difference instead of dirty here, I'm going to use touched. Action.

The form input is considered touched when the user has entered their mouse inside of that form input. So that just gives you another option for determining when you want to actually display the error message. App. We can also tell when a form is valid. By calling sign up form valid, we can determine if the entire form is valid as well as all of the inputs contained inside of it.

App. As a final touch, we'll disable the submit button so the user can't accidentally submit an invalid form. When the user submits their form and they're successfully authenticated, app. It's going to hide this initial form and then bring up our secondary form here. So for this one, we'll bind it to the set catchphrase method app.

And then we'll go ahead and add the FormControl name and then another submit button for that as well. The end result looks something like this. App. We start typing in the form and then we get this validation error until we actually enter a valid email then it has the green border. App.

Then we go ahead and enter our password and we get the green message that the form looks good. So now we authenticate in Firebase and then it brings up the secondary form. App. The sign up process works as expected at this point, but we still want to set up a router guard to prevent our users from navigating away from the form if they haven't fully completed it. App.

We can do that by setting up an auth guard that we'll use in our app routing module. Guards use the injectable decorator, so they behave just like services do in Angular. App. First, I'm going to import it into the module and then add it to the provider's array. Then you can use the guard on individual routes by setting the can activate property, and you just pass it to its array of guards.

Now we can go into the actual auth guard file, app. And we're going to import our auth service. And if you remember from earlier, our auth service provides a user observable. So what we're going to do is convert app. That user observable into a boolean that's going to determine whether or not a user is authorized to visit a certain route.

App. So we're going to inject the auth service in the constructor, and then we're going to use the Angular router as well as that notification service that I was talking about earlier. App. The CanActivate method inside the guard needs to return a Boolean Observable. So we first take our User Observable and then we map it down to a Boolean, app.

And we determine this Boolean by whether or not the user has that catch phrase property on their user document. We convert the property to a Boolean by adding a double bang in front of it. App. If this evaluates to false, we're going to use the router as well as the notification service to redirect the user back to the form and then show them an error message. App.

The end result is that any routes that have this guard applied to it will not be activated unless the user has that catch phrase property on their document in Firestore. App. That's only going to secure routes on the front end. If you have truly sensitive information there, you'll want to also send a back end database rule. App.

In this case, you can check if the catch phrase exists on the current user's document by pointing to the user document with the request auth UID. ID. If it's not there, the user won't be able to read or write any documents associated with this rule. That's it app. For multistep authentication with Firebase, if this video helped you, please like and subscribe.

And if you wanna learn more, consider becoming a pro member at angularfirebase.com. You You'll get a free copy of my book as well as 1 on 1 project support. Thanks for watching, and I'll see you soon. App.
Firebase makes basic user authentication very easy, but what happens if you require additional data from your user before they're authorized to start using your app. In this episode, I'm going to set up a multi step sign up form that requires the user to fill out a catchphrase on their user profile before they're authorized to start using the app.
App. Then we're going to secure all the application data on both the front end and the back end. This feature works by setting up a custom user document in the Firestore database. We can then verify that the current user has the correct information on their document before they're authorized to perform certain actions.
security
In order to build this feature, app. I'm going to be using the Firestarter demo app, which is on GitHub. You can clone it if you want, but this code can be applied to any Angular app that's using Firebase.
App. Before we get started, make sure to subscribe, and you can find all the source code at angularfirebase.com. The first place we're going to start is in the auth service, app. And in my case, it's in the core module. The goal of the service is to keep track of the current user and give them the ability to sign in via email and password. App. The important imports to take note of here are AngularFire auth and AngularFirestore as well as the switch map operator from RxJS.
software
App. The first thing I'm going to do is set up an interface to model our user data. We need to have a user ID and email address, which we'll get from Firebase auth, and then our custom piece of data is the catchphrase. Notice that you don't need to actually add the password to the user interface. That's all handled by AngularFire auth. App. So our actual user is going to be an observable type to this interface, then we'll inject our dependencies in the constructor. The notify service that I'm adding here is part of the demo app. App. It's not required, but it's used to show the end user any problems with the sign in process. Then inside the constructor, we'll define the user variable. App. So we do this by calling AngularFireAuthState, which gives us an observable that we can call switch map on. If the current user is logged in, app. Then we'll go ahead and retrieve the user data from Firestore. We do that by calling a f s doc and then point to that current user's user ID app and then call value changes to get the observable. If the user is not logged in, then we're just going to return an observable of null. App. That chunk of code is going to keep track of the current user at the global level throughout our application.
It's easy for things to go wrong with email password auth. For example, the user might try to log in end with an email address that's already been taken. When that happens, we're going to use this helper method to notify the user in the front end. After that, We're going to create another helper method that will create a new user document when the user first signs up.
email
When the user signs up, Firebase will give us a user object. App. We can then use that object to point to a document in Firestore. At this point, we're only gonna have the user's email address and user ID, so we'll go ahead and set that to an object. App. Then we can update the document in Firestore. Now we need a way to create a new user by having them log in with an email address and a password. App. So we'll create a method that will handle this data and then we can call AngularFire auth create user with email and password. App. This is going to return a Promise and if it's successful, it will return the user object. And then we'll go ahead and use that user object app to create the user document in that helper method that we just defined. And lastly, we'll catch any errors and notify the user if there's any problem with the sign up. App. That handles the first part of the sign up, but if you have additional steps, you'll need a method to update data on that user document. App. This method will take the current user as well as the data that we wanna update, and then we'll point to that user's user ID in Firestore and update the data. App. Now let's jump over to the user form component and put the service to use. 1st, I wanna show you how it's set up in the router. So here I'm in the app routing module, app. And I have 3 unrelated components that we're going to lock down for unauthorized users later. And then our user form component, we're going to load at the login path. App. We're going to come back here a little bit later to add a router guard to secure all of these routes. Then you'll also need to go into whichever NG module uses this component app and import the Reactive Forms module from Angular forms. Now we can start writing this component. First, we need the auth service, app. And we also need a few reactive forms pieces, including form group, form builder, and validators. The component is going to use 2 separate form groups. App. So the first form will be the sign up form, and the second form will be the detail form where we collect any additional information we want from the user. In this case, we're only collecting the catchphrase property, but you could collect any information you want there. Then we'll inject Form Builder in the constructor as well as the auth service. App. To create a reactive form, you call form builder group, and then you pass it an object where each key is a corresponding form field. So in this case, we have an email input. Then app. Then we set its value equal to an array where the first value in that array is an empty string, and then the second value is another array of validators.
App. These validators are based on their HTML counterparts. In this case, we are going to validate the email as required and that it has an email format. App. For the password, we're going to use a regular expression, which just validates that there's at least one number present in the password string.
email
And And then we're also gonna validate that it has a minimum length of 6 and a max length of 25. Then we'll set up the second form in exactly the same way, but it's actually much assembler. We'll just say detail form is the Form Builder group, and its only field is going to be the catch phrase, which is required. App. And that's all it takes to set up a reactive form. It's just a series of form fields that are defined directly in your TypeScript. The main problem is that they generally create a lot of TypeScript code. So we can cut down on this code at least a little bit by using getters. So we'll call sign up form get email, app. And we'll repeat this pattern for each individual form field. When we get to the actual form HTML, you'll see that this drastically cuts down on the amount of code that we need to use in the template.
The last thing we need is an event handler for when these forms are submitted. So when they submit the sign form, we'll call our email sign up method from the service with their email value and password value. And for the catch phrase, we simply call the auth service update user method with the catch phrase that they enter into that form.
email
Now we're going to switch over to the HTML, and I'll show you how to use this reactive form in the template. App. I'm going to set up an NG container that's going to wrap both of the forms. The reason for this is that we can unwrap the user observable to apply some conditional logic to determine which form to show. So we'll do that by calling auth user async or we're going to show an empty object if the user is null. And then we're gonna set that to the user template variable. App. I realize that looks kind of weird, but it is a very useful technique in Angular. The next thing we'll do is set up our form group. App. So we do that by calling form group with our sign up form. This form should only be shown if we don't have a user ID, meaning the user has no Firebase account at all. App. Then I'm going to add the detail form right below it, and we're only gonna show this form if the user is authenticated, but they still don't have the catch phrase on their user document. App. Then I'll set up one more block here, and this one will show if the user is logged in and they have a catch phrase, meaning the form is 100% complete. App. You could extract this into separate components, but I'm just showing it all in one go here just to keep this as simple as possible.
Going back to the sign up form, we'll app. First, find our sign up method to the NG submit event. Then we'll set a label and a form input for the email address. App. We connect this input to our reactive form in the TypeScript by calling form control name followed by email.
email
Because we set validators on this form, we can determine whether or app. It is in a valid state based on the user's input. When the form is not valid, we want to show an error message, and we only wanna show it if the form is dirty, app, which means that the user has started typing into that Form Input. Then we'll go and do the same exact thing for the password, but the only difference instead of dirty here, I'm going to use touched. Action. The form input is considered touched when the user has entered their mouse inside of that form input. So that just gives you another option for determining when you want to actually display the error message. App. We can also tell when a form is valid. By calling sign up form valid, we can determine if the entire form is valid as well as all of the inputs contained inside of it. App. As a final touch, we'll disable the submit button so the user can't accidentally submit an invalid form. When the user submits their form and they're successfully authenticated, app. It's going to hide this initial form and then bring up our secondary form here. So for this one, we'll bind it to the set catchphrase method app. And then we'll go ahead and add the FormControl name and then another submit button for that as well. The end result looks something like this. App. We start typing in the form and then we get this validation error until we actually enter a valid email then it has the green border. App. Then we go ahead and enter our password and we get the green message that the form looks good. So now we authenticate in Firebase and then it brings up the secondary form. App. The sign up process works as expected at this point, but we still want to set up a router guard to prevent our users from navigating away from the form if they haven't fully completed it. App. We can do that by setting up an auth guard that we'll use in our app routing module. Guards use the injectable decorator, so they behave just like services do in Angular. App. First, I'm going to import it into the module and then add it to the provider's array. Then you can use the guard on individual routes by setting the can activate property, and you just pass it to its array of guards.
Now we can go into the actual auth guard file, app. And we're going to import our auth service. And if you remember from earlier, our auth service provides a user observable. So what we're going to do is convert app. That user observable into a boolean that's going to determine whether or not a user is authorized to visit a certain route.
software
App. So we're going to inject the auth service in the constructor, and then we're going to use the Angular router as well as that notification service that I was talking about earlier. App. The CanActivate method inside the guard needs to return a Boolean Observable. So we first take our User Observable and then we map it down to a Boolean, app. And we determine this Boolean by whether or not the user has that catch phrase property on their user document. We convert the property to a Boolean by adding a double bang in front of it. App. If this evaluates to false, we're going to use the router as well as the notification service to redirect the user back to the form and then show them an error message.
App. The end result is that any routes that have this guard applied to it will not be activated unless the user has that catch phrase property on their document in Firestore. App. That's only going to secure routes on the front end. If you have truly sensitive information there, you'll want to also send a back end database rule. App. In this case, you can check if the catch phrase exists on the current user's document by pointing to the user document with the request auth UID.
security
law enforcement
databases
ID. If it's not there, the user won't be able to read or write any documents associated with this rule. That's it app. For multistep authentication with Firebase, if this video helped you, please like and subscribe. And if you wanna learn more, consider becoming a pro member at angularfirebase.com. You You'll get a free copy of my book as well as 1 on 1 project support.
Thanks for watching, and I'll see you soon. App.
Firebase makes basic user authentication very easy, but what happens if you require additional data from your user before they're authorized to start using your app. In this episode, I'm going to set up a multi step sign up form that requires the user to fill out a catchphrase on their user profile before they're authorized to start using the app. App. Then we're going to secure all the application data on both the front end and the back end. This feature works by setting up a custom user document in the Firestore database. We can then verify that the current user has the correct information on their document before they're authorized to perform certain actions. In order to build this feature, app. I'm going to be using the Firestarter demo app, which is on GitHub. You can clone it if you want, but this code can be applied to any Angular app that's using Firebase. App. Before we get started, make sure to subscribe, and you can find all the source code at angularfirebase.com. The first place we're going to start is in the auth service, app. And in my case, it's in the core module. The goal of the service is to keep track of the current user and give them the ability to sign in via email and password. App. The important imports to take note of here are AngularFire auth and AngularFirestore as well as the switch map operator from RxJS. App. The first thing I'm going to do is set up an interface to model our user data. We need to have a user ID and email address, which we'll get from Firebase auth, and then our custom piece of data is the catchphrase. Notice that you don't need to actually add the password to the user interface. That's all handled by AngularFire auth. App. So our actual user is going to be an observable type to this interface, then we'll inject our dependencies in the constructor. The notify service that I'm adding here is part of the demo app. App. It's not required, but it's used to show the end user any problems with the sign in process. Then inside the constructor, we'll define the user variable. App. So we do this by calling AngularFireAuthState, which gives us an observable that we can call switch map on. If the current user is logged in, app. Then we'll go ahead and retrieve the user data from Firestore. We do that by calling a f s doc and then point to that current user's user ID app and then call value changes to get the observable. If the user is not logged in, then we're just going to return an observable of null. App. That chunk of code is going to keep track of the current user at the global level throughout our application. It's easy for things to go wrong with email password auth. For example, the user might try to log in end with an email address that's already been taken. When that happens, we're going to use this helper method to notify the user in the front end. After that, We're going to create another helper method that will create a new user document when the user first signs up. When the user signs up, Firebase will give us a user object. App. We can then use that object to point to a document in Firestore. At this point, we're only gonna have the user's email address and user ID, so we'll go ahead and set that to an object. App. Then we can update the document in Firestore. Now we need a way to create a new user by having them log in with an email address and a password. App. So we'll create a method that will handle this data and then we can call AngularFire auth create user with email and password. App. This is going to return a Promise and if it's successful, it will return the user object. And then we'll go ahead and use that user object app to create the user document in that helper method that we just defined. And lastly, we'll catch any errors and notify the user if there's any problem with the sign up. App. That handles the first part of the sign up, but if you have additional steps, you'll need a method to update data on that user document. App. This method will take the current user as well as the data that we wanna update, and then we'll point to that user's user ID in Firestore and update the data. App. Now let's jump over to the user form component and put the service to use. 1st, I wanna show you how it's set up in the router. So here I'm in the app routing module, app. And I have 3 unrelated components that we're going to lock down for unauthorized users later. And then our user form component, we're going to load at the login path. App. We're going to come back here a little bit later to add a router guard to secure all of these routes. Then you'll also need to go into whichever NG module uses this component app and import the Reactive Forms module from Angular forms. Now we can start writing this component. First, we need the auth service, app. And we also need a few reactive forms pieces, including form group, form builder, and validators. The component is going to use 2 separate form groups. App. So the first form will be the sign up form, and the second form will be the detail form where we collect any additional information we want from the user. In this case, we're only collecting the catchphrase property, but you could collect any information you want there. Then we'll inject Form Builder in the constructor as well as the auth service. App. To create a reactive form, you call form builder group, and then you pass it an object where each key is a corresponding form field. So in this case, we have an email input. Then app. Then we set its value equal to an array where the first value in that array is an empty string, and then the second value is another array of validators. App. These validators are based on their HTML counterparts. In this case, we are going to validate the email as required and that it has an email format. App. For the password, we're going to use a regular expression, which just validates that there's at least one number present in the password string. And And then we're also gonna validate that it has a minimum length of 6 and a max length of 25. Then we'll set up the second form in exactly the same way, but it's actually much assembler. We'll just say detail form is the Form Builder group, and its only field is going to be the catch phrase, which is required. App. And that's all it takes to set up a reactive form. It's just a series of form fields that are defined directly in your TypeScript. The main problem is that they generally create a lot of TypeScript code. So we can cut down on this code at least a little bit by using getters. So we'll call sign up form get email, app. And we'll repeat this pattern for each individual form field. When we get to the actual form HTML, you'll see that this drastically cuts down on the amount of code that we need to use in the template. The last thing we need is an event handler for when these forms are submitted. So when they submit the sign form, we'll call our email sign up method from the service with their email value and password value. And for the catch phrase, we simply call the auth service update user method with the catch phrase that they enter into that form. Now we're going to switch over to the HTML, and I'll show you how to use this reactive form in the template. App. I'm going to set up an NG container that's going to wrap both of the forms. The reason for this is that we can unwrap the user observable to apply some conditional logic to determine which form to show. So we'll do that by calling auth user async or we're going to show an empty object if the user is null. And then we're gonna set that to the user template variable. App. I realize that looks kind of weird, but it is a very useful technique in Angular. The next thing we'll do is set up our form group. App. So we do that by calling form group with our sign up form. This form should only be shown if we don't have a user ID, meaning the user has no Firebase account at all. App. Then I'm going to add the detail form right below it, and we're only gonna show this form if the user is authenticated, but they still don't have the catch phrase on their user document. App. Then I'll set up one more block here, and this one will show if the user is logged in and they have a catch phrase, meaning the form is 100% complete. App. You could extract this into separate components, but I'm just showing it all in one go here just to keep this as simple as possible. Going back to the sign up form, we'll app. First, find our sign up method to the NG submit event. Then we'll set a label and a form input for the email address. App. We connect this input to our reactive form in the TypeScript by calling form control name followed by email. Because we set validators on this form, we can determine whether or app. It is in a valid state based on the user's input. When the form is not valid, we want to show an error message, and we only wanna show it if the form is dirty, app, which means that the user has started typing into that Form Input. Then we'll go and do the same exact thing for the password, but the only difference instead of dirty here, I'm going to use touched. Action. The form input is considered touched when the user has entered their mouse inside of that form input. So that just gives you another option for determining when you want to actually display the error message. App. We can also tell when a form is valid. By calling sign up form valid, we can determine if the entire form is valid as well as all of the inputs contained inside of it. App. As a final touch, we'll disable the submit button so the user can't accidentally submit an invalid form. When the user submits their form and they're successfully authenticated, app. It's going to hide this initial form and then bring up our secondary form here. So for this one, we'll bind it to the set catchphrase method app. And then we'll go ahead and add the FormControl name and then another submit button for that as well. The end result looks something like this. App. We start typing in the form and then we get this validation error until we actually enter a valid email then it has the green border. App. Then we go ahead and enter our password and we get the green message that the form looks good. So now we authenticate in Firebase and then it brings up the secondary form. App. The sign up process works as expected at this point, but we still want to set up a router guard to prevent our users from navigating away from the form if they haven't fully completed it. App. We can do that by setting up an auth guard that we'll use in our app routing module. Guards use the injectable decorator, so they behave just like services do in Angular. App. First, I'm going to import it into the module and then add it to the provider's array. Then you can use the guard on individual routes by setting the can activate property, and you just pass it to its array of guards. Now we can go into the actual auth guard file, app. And we're going to import our auth service. And if you remember from earlier, our auth service provides a user observable. So what we're going to do is convert app. That user observable into a boolean that's going to determine whether or not a user is authorized to visit a certain route. App. So we're going to inject the auth service in the constructor, and then we're going to use the Angular router as well as that notification service that I was talking about earlier. App. The CanActivate method inside the guard needs to return a Boolean Observable. So we first take our User Observable and then we map it down to a Boolean, app. And we determine this Boolean by whether or not the user has that catch phrase property on their user document. We convert the property to a Boolean by adding a double bang in front of it. App. If this evaluates to false, we're going to use the router as well as the notification service to redirect the user back to the form and then show them an error message. App. The end result is that any routes that have this guard applied to it will not be activated unless the user has that catch phrase property on their document in Firestore. App. That's only going to secure routes on the front end. If you have truly sensitive information there, you'll want to also send a back end database rule. App. In this case, you can check if the catch phrase exists on the current user's document by pointing to the user document with the request auth UID. ID. If it's not there, the user won't be able to read or write any documents associated with this rule. That's it app. For multistep authentication with Firebase, if this video helped you, please like and subscribe. And if you wanna learn more, consider becoming a pro member at angularfirebase.com. You You'll get a free copy of my book as well as 1 on 1 project support. Thanks for watching, and I'll see you soon. App.
Firebase
firebase
makes
makes
basic
basic
user
user
authentication
authentication
very
very
easy,
easy
but
but
what
what
happens
happens
if
if
you
you
require
require
additional
additional
data
data
from
from
your
your
user
user
before
before
they're
they're
authorized
authorized
to
to
start
start
using
using
your
your
app.
app
In
in
this
this
episode,
episode
I'm
i'm
going
going
to
to
set
set
up
up
a
a
multi
multi
step
step
sign
sign
up
up
form
form
that
that
requires
requires
the
the
user
user
to
to
fill
fill
out
out
a
a
catchphrase
catchphrase
on
on
their
their
user
user
profile
profile
before
before
they're
they're
authorized
authorized
to
to
start
start
using
using
the
the
app.
app
App.
app
Then
then
we're
we're
going
going
to
to
secure
secure
all
all
the
the
application
application
data
data
on
on
both
both
the
the
front
front
end
end
and
and
the
the
back
back
end.
end
This
this
feature
feature
works
works
by
by
setting
setting
up
up
a
a
custom
custom
user
user
document
document
in
in
the
the
Firestore
firestore
database.
database
We
we
can
can
then
then
verify
verify
that
that
the
the
current
current
user
user
has
has
the
the
correct
correct
information
information
on
on
their
their
document
document
before
before
they're
they're
authorized
authorized
to
to
perform
perform
certain
certain
actions.
actions
In
in
order
order
to
to
build
build
this
this
feature,
feature
app.
app
I'm
i'm
going
going
to
to
be
be
using
using
the
the
Firestarter
firestarter
demo
demo
app,
app
which
which
is
is
on
on
GitHub.
github
You
you
can
can
clone
clone
it
it
if
if
you
you
want,
want
but
but
this
this
code
code
can
can
be
be
applied
applied
to
to
any
any
Angular
angular
app
app
that's
that's
using
using
Firebase.
firebase
App.
app
Before
before
we
we
get
get
started,
started
make
make
sure
sure
to
to
subscribe,
subscribe
and
and
you
you
can
can
find
find
all
all
the
the
source
source
code
code
at
at
angularfirebase.com.
angularfirebase.com
The
the
first
first
place
place
we're
we're
going
going
to
to
start
start
is
is
in
in
the
the
auth
auth
service,
service
app.
app
And
and
in
in
my
my
case,
case
it's
it's
in
in
the
the
core
core
module.
module
The
the
goal
goal
of
of
the
the
service
service
is
is
to
to
keep
keep
track
track
of
of
the
the
current
current
user
user
and
and
give
give
them
them
the
the
ability
ability
to
to
sign
sign
in
in
via
via
email
email
and
and
password.
password
App.
app
The
the
important
important
imports
imports
to
to
take
take
note
note
of
of
here
here
are
are
AngularFire
angularfire
auth
auth
and
and
AngularFirestore
angularfirestore
as
as
well
well
as
as
the
the
switch
switch
map
map
operator
operator
from
from
RxJS.
rxjs
App.
app
The
the
first
first
thing
thing
I'm
i'm
going
going
to
to
do
do
is
is
set
set
up
up
an
an
interface
interface
to
to
model
model
our
our
user
user
data.
data
We
we
need
need
to
to
have
have
a
a
user
user
ID
id
and
and
email
email
address,
address
which
which
we'll
we'll
get
get
from
from
Firebase
firebase
auth,
auth
and
and
then
then
our
our
custom
custom
piece
piece
of
of
data
data
is
is
the
the
catchphrase.
catchphrase
Notice
notice
that
that
you
you
don't
don't
need
need
to
to
actually
actually
add
add
the
the
password
password
to
to
the
the
user
user
interface.
interface
That's
that's
all
all
handled
handled
by
by
AngularFire
angularfire
auth.
auth
App.
app
So
so
our
our
actual
actual
user
user
is
is
going
going
to
to
be
be
an
an
observable
observable
type
type
to
to
this
this
interface,
interface
then
then
we'll
we'll
inject
inject
our
our
dependencies
dependencies
in
in
the
the
constructor.
constructor
The
the
notify
notify
service
service
that
that
I'm
i'm
adding
adding
here
here
is
is
part
part
of
of
the
the
demo
demo
app.
app
App.
app
It's
it's
not
not
required,
required
but
but
it's
it's
used
used
to
to
show
show
the
the
end
end
user
user
any
any
problems
problems
with
with
the
the
sign
sign
in
in
process.
process
Then
then
inside
inside
the
the
constructor,
constructor
we'll
we'll
define
define
the
the
user
user
variable.
variable
App.
app
So
so
we
we
do
do
this
this
by
by
calling
calling
AngularFireAuthState,
angularfireauthstate
which
which
gives
gives
us
us
an
an
observable
observable
that
that
we
we
can
can
call
call
switch
switch
map
map
on.
on
If
if
the
the
current
current
user
user
is
is
logged
logged
in,
in
app.
app
Then
then
we'll
we'll
go
go
ahead
ahead
and
and
retrieve
retrieve
the
the
user
user
data
data
from
from
Firestore.
firestore
We
we
do
do
that
that
by
by
calling
calling
a
a
f
f
s
s
doc
doc
and
and
then
then
point
point
to
to
that
that
current
current
user's
user's
user
user
ID
id
app
app
and
and
then
then
call
call
value
value
changes
changes
to
to
get
get
the
the
observable.
observable
If
if
the
the
user
user
is
is
not
not
logged
logged
in,
in
then
then
we're
we're
just
just
going
going
to
to
return
return
an
an
observable
observable
of
of
null.
null
App.
app
That
that
chunk
chunk
of
of
code
code
is
is
going
going
to
to
keep
keep
track
track
of
of
the
the
current
current
user
user
at
at
the
the
global
global
level
level
throughout
throughout
our
our
application.
application
It's
it's
easy
easy
for
for
things
things
to
to
go
go
wrong
wrong
with
with
email
email
password
password
auth.
auth
For
for
example,
example
the
the
user
user
might
might
try
try
to
to
log
log
in
in
end
end
with
with
an
an
email
email
address
address
that's
that's
already
already
been
been
taken.
taken
When
when
that
that
happens,
happens
we're
we're
going
going
to
to
use
use
this
this
helper
helper
method
method
to
to
notify
notify
the
the
user
user
in
in
the
the
front
front
end.
end
After
after
that,
that
We're
we're
going
going
to
to
create
create
another
another
helper
helper
method
method
that
that
will
will
create
create
a
a
new
new
user
user
document
document
when
when
the
the
user
user
first
first
signs
signs
up.
up
When
when
the
the
user
user
signs
signs
up,
up
Firebase
firebase
will
will
give
give
us
us
a
a
user
user
object.
object
App.
app
We
we
can
can
then
then
use
use
that
that
object
object
to
to
point
point
to
to
a
a
document
document
in
in
Firestore.
firestore
At
at
this
this
point,
point
we're
we're
only
only
gonna
gonna
have
have
the
the
user's
user's
email
email
address
address
and
and
user
user
ID,
id
so
so
we'll
we'll
go
go
ahead
ahead
and
and
set
set
that
that
to
to
an
an
object.
object
App.
app
Then
then
we
we
can
can
update
update
the
the
document
document
in
in
Firestore.
firestore
Now
now
we
we
need
need
a
a
way
way
to
to
create
create
a
a
new
new
user
user
by
by
having
having
them
them
log
log
in
in
with
with
an
an
email
email
address
address
and
and
a
a
password.
password
App.
app
So
so
we'll
we'll
create
create
a
a
method
method
that
that
will
will
handle
handle
this
this
data
data
and
and
then
then
we
we
can
can
call
call
AngularFire
angularfire
auth
auth
create
create
user
user
with
with
email
email
and
and
password.
password
App.
app
This
this
is
is
going
going
to
to
return
return
a
a
Promise
promise
and
and
if
if
it's
it's
successful,
successful
it
it
will
will
return
return
the
the
user
user
object.
object
And
and
then
then
we'll
we'll
go
go
ahead
ahead
and
and
use
use
that
that
user
user
object
object
app
app
to
to
create
create
the
the
user
user
document
document
in
in
that
that
helper
helper
method
method
that
that
we
we
just
just
defined.
defined
And
and
lastly,
lastly
we'll
we'll
catch
catch
any
any
errors
errors
and
and
notify
notify
the
the
user
user
if
if
there's
there's
any
any
problem
problem
with
with
the
the
sign
sign
up.
up
App.
app
That
that
handles
handles
the
the
first
first
part
part
of
of
the
the
sign
sign
up,
up
but
but
if
if
you
you
have
have
additional
additional
steps,
steps
you'll
you'll
need
need
a
a
method
method
to
to
update
update
data
data
on
on
that
that
user
user
document.
document
App.
app
This
this
method
method
will
will
take
take
the
the
current
current
user
user
as
as
well
well
as
as
the
the
data
data
that
that
we
we
wanna
wanna
update,
update
and
and
then
then
we'll
we'll
point
point
to
to
that
that
user's
user's
user
user
ID
id
in
in
Firestore
firestore
and
and
update
update
the
the
data.
data
App.
app
Now
now
let's
let's
jump
jump
over
over
to
to
the
the
user
user
form
form
component
component
and
and
put
put
the
the
service
service
to
to
use.
use
1st,
1st
I
i
wanna
wanna
show
show
you
you
how
how
it's
it's
set
set
up
up
in
in
the
the
router.
router
So
so
here
here
I'm
i'm
in
in
the
the
app
app
routing
routing
module,
module
app.
app
And
and
I
i
have
have
3
3
unrelated
unrelated
components
components
that
that
we're
we're
going
going
to
to
lock
lock
down
down
for
for
unauthorized
unauthorized
users
users
later.
later
And
and
then
then
our
our
user
user
form
form
component,
component
we're
we're
going
going
to
to
load
load
at
at
the
the
login
login
path.
path
App.
app
We're
we're
going
going
to
to
come
come
back
back
here
here
a
a
little
little
bit
bit
later
later
to
to
add
add
a
a
router
router
guard
guard
to
to
secure
secure
all
all
of
of
these
these
routes.
routes
Then
then
you'll
you'll
also
also
need
need
to
to
go
go
into
into
whichever
whichever
NG
ng
module
module
uses
uses
this
this
component
component
app
app
and
and
import
import
the
the
Reactive
reactive
Forms
forms
module
module
from
from
Angular
angular
forms.
forms
Now
now
we
we
can
can
start
start
writing
writing
this
this
component.
component
First,
first
we
we
need
need
the
the
auth
auth
service,
service
app.
app
And
and
we
we
also
also
need
need
a
a
few
few
reactive
reactive
forms
forms
pieces,
pieces
including
including
form
form
group,
group
form
form
builder,
builder
and
and
validators.
validators
The
the
component
component
is
is
going
going
to
to
use
use
2
2
separate
separate
form
form
groups.
groups
App.
app
So
so
the
the
first
first
form
form
will
will
be
be
the
the
sign
sign
up
up
form,
form
and
and
the
the
second
second
form
form
will
will
be
be
the
the
detail
detail
form
form
where
where
we
we
collect
collect
any
any
additional
additional
information
information
we
we
want
want
from
from
the
the
user.
user
In
in
this
this
case,
case
we're
we're
only
only
collecting
collecting
the
the
catchphrase
catchphrase
property,
property
but
but
you
you
could
could
collect
collect
any
any
information
information
you
you
want
want
there.
there
Then
then
we'll
we'll
inject
inject
Form
form
Builder
builder
in
in
the
the
constructor
constructor
as
as
well
well
as
as
the
the
auth
auth
service.
service
App.
app
To
to
create
create
a
a
reactive
reactive
form,
form
you
you
call
call
form
form
builder
builder
group,
group
and
and
then
then
you
you
pass
pass
it
it
an
an
object
object
where
where
each
each
key
key
is
is
a
a
corresponding
corresponding
form
form
field.
field
So
so
in
in
this
this
case,
case
we
we
have
have
an
an
email
email
input.
input
Then
then
app.
app
Then
then
we
we
set
set
its
its
value
value
equal
equal
to
to
an
an
array
array
where
where
the
the
first
first
value
value
in
in
that
that
array
array
is
is
an
an
empty
empty
string,
string
and
and
then
then
the
the
second
second
value
value
is
is
another
another
array
array
of
of
validators.
validators
App.
app
These
these
validators
validators
are
are
based
based
on
on
their
their
HTML
html
counterparts.
counterparts
In
in
this
this
case,
case
we
we
are
are
going
going
to
to
validate
validate
the
the
email
email
as
as
required
required
and
and
that
that
it
it
has
has
an
an
email
email
format.
format
App.
app
For
for
the
the
password,
password
we're
we're
going
going
to
to
use
use
a
a
regular
regular
expression,
expression
which
which
just
just
validates
validates
that
that
there's
there's
at
at
least
least
one
one
number
number
present
present
in
in
the
the
password
password
string.
string
And
and
And
and
then
then
we're
we're
also
also
gonna
gonna
validate
validate
that
that
it
it
has
has
a
a
minimum
minimum
length
length
of
of
6
6
and
and
a
a
max
max
length
length
of
of
25.
25
Then
then
we'll
we'll
set
set
up
up
the
the
second
second
form
form
in
in
exactly
exactly
the
the
same
same
way,
way
but
but
it's
it's
actually
actually
much
much
assembler.
assembler
We'll
we'll
just
just
say
say
detail
detail
form
form
is
is
the
the
Form
form
Builder
builder
group,
group
and
and
its
its
only
only
field
field
is
is
going
going
to
to
be
be
the
the
catch
catch
phrase,
phrase
which
which
is
is
required.
required
App.
app
And
and
that's
that's
all
all
it
it
takes
takes
to
to
set
set
up
up
a
a
reactive
reactive
form.
form
It's
it's
just
just
a
a
series
series
of
of
form
form
fields
fields
that
that
are
are
defined
defined
directly
directly
in
in
your
your
TypeScript.
typescript
The
the
main
main
problem
problem
is
is
that
that
they
they
generally
generally
create
create
a
a
lot
lot
of
of
TypeScript
typescript
code.
code
So
so
we
we
can
can
cut
cut
down
down
on
on
this
this
code
code
at
at
least
least
a
a
little
little
bit
bit
by
by
using
using
getters.
getters
So
so
we'll
we'll
call
call
sign
sign
up
up
form
form
get
get
email,
email
app.
app
And
and
we'll
we'll
repeat
repeat
this
this
pattern
pattern
for
for
each
each
individual
individual
form
form
field.
field
When
when
we
we
get
get
to
to
the
the
actual
actual
form
form
HTML,
html
you'll
you'll
see
see
that
that
this
this
drastically
drastically
cuts
cuts
down
down
on
on
the
the
amount
amount
of
of
code
code
that
that
we
we
need
need
to
to
use
use
in
in
the
the
template.
template
The
the
last
last
thing
thing
we
we
need
need
is
is
an
an
event
event
handler
handler
for
for
when
when
these
these
forms
forms
are
are
submitted.
submitted
So
so
when
when
they
they
submit
submit
the
the
sign
sign
form,
form
we'll
we'll
call
call
our
our
email
email
sign
sign
up
up
method
method
from
from
the
the
service
service
with
with
their
their
email
email
value
value
and
and
password
password
value.
value
And
and
for
for
the
the
catch
catch
phrase,
phrase
we
we
simply
simply
call
call
the
the
auth
auth
service
service
update
update
user
user
method
method
with
with
the
the
catch
catch
phrase
phrase
that
that
they
they
enter
enter
into
into
that
that
form.
form
Now
now
we're
we're
going
going
to
to
switch
switch
over
over
to
to
the
the
HTML,
html
and
and
I'll
i'll
show
show
you
you
how
how
to
to
use
use
this
this
reactive
reactive
form
form
in
in
the
the
template.
template
App.
app
I'm
i'm
going
going
to
to
set
set
up
up
an
an
NG
ng
container
container
that's
that's
going
going
to
to
wrap
wrap
both
both
of
of
the
the
forms.
forms
The
the
reason
reason
for
for
this
this
is
is
that
that
we
we
can
can
unwrap
unwrap
the
the
user
user
observable
observable
to
to
apply
apply
some
some
conditional
conditional
logic
logic
to
to
determine
determine
which
which
form
form
to
to
show.
show
So
so
we'll
we'll
do
do
that
that
by
by
calling
calling
auth
auth
user
user
async
async
or
or
we're
we're
going
going
to
to
show
show
an
an
empty
empty
object
object
if
if
the
the
user
user
is
is
null.
null
And
and
then
then
we're
we're
gonna
gonna
set
set
that
that
to
to
the
the
user
user
template
template
variable.
variable
App.
app
I
i
realize
realize
that
that
looks
looks
kind
kind
of
of
weird,
weird
but
but
it
it
is
is
a
a
very
very
useful
useful
technique
technique
in
in
Angular.
angular
The
the
next
next
thing
thing
we'll
we'll
do
do
is
is
set
set
up
up
our
our
form
form
group.
group
App.
app
So
so
we
we
do
do
that
that
by
by
calling
calling
form
form
group
group
with
with
our
our
sign
sign
up
up
form.
form
This
this
form
form
should
should
only
only
be
be
shown
shown
if
if
we
we
don't
don't
have
have
a
a
user
user
ID,
id
meaning
meaning
the
the
user
user
has
has
no
no
Firebase
firebase
account
account
at
at
all.
all
App.
app
Then
then
I'm
i'm
going
going
to
to
add
add
the
the
detail
detail
form
form
right
right
below
below
it,
it
and
and
we're
we're
only
only
gonna
gonna
show
show
this
this
form
form
if
if
the
the
user
user
is
is
authenticated,
authenticated
but
but
they
they
still
still
don't
don't
have
have
the
the
catch
catch
phrase
phrase
on
on
their
their
user
user
document.
document
App.
app
Then
then
I'll
i'll
set
set
up
up
one
one
more
more
block
block
here,
here
and
and
this
this
one
one
will
will
show
show
if
if
the
the
user
user
is
is
logged
logged
in
in
and
and
they
they
have
have
a
a
catch
catch
phrase,
phrase
meaning
meaning
the
the
form
form
is
is
100%
100%
complete.
complete
App.
app
You
you
could
could
extract
extract
this
this
into
into
separate
separate
components,
components
but
but
I'm
i'm
just
just
showing
showing
it
it
all
all
in
in
one
one
go
go
here
here
just
just
to
to
keep
keep
this
this
as
as
simple
simple
as
as
possible.
possible
Going
going
back
back
to
to
the
the
sign
sign
up
up
form,
form
we'll
we'll
app.
app
First,
first
find
find
our
our
sign
sign
up
up
method
method
to
to
the
the
NG
ng
submit
submit
event.
event
Then
then
we'll
we'll
set
set
a
a
label
label
and
and
a
a
form
form
input
input
for
for
the
the
email
email
address.
address
App.
app
We
we
connect
connect
this
this
input
input
to
to
our
our
reactive
reactive
form
form
in
in
the
the
TypeScript
typescript
by
by
calling
calling
form
form
control
control
name
name
followed
followed
by
by
email.
email
Because
because
we
we
set
set
validators
validators
on
on
this
this
form,
form
we
we
can
can
determine
determine
whether
whether
or
or
app.
app
It
it
is
is
in
in
a
a
valid
valid
state
state
based
based
on
on
the
the
user's
user's
input.
input
When
when
the
the
form
form
is
is
not
not
valid,
valid
we
we
want
want
to
to
show
show
an
an
error
error
message,
message
and
and
we
we
only
only
wanna
wanna
show
show
it
it
if
if
the
the
form
form
is
is
dirty,
dirty
app,
app
which
which
means
means
that
that
the
the
user
user
has
has
started
started
typing
typing
into
into
that
that
Form
form
Input.
input
Then
then
we'll
we'll
go
go
and
and
do
do
the
the
same
same
exact
exact
thing
thing
for
for
the
the
password,
password
but
but
the
the
only
only
difference
difference
instead
instead
of
of
dirty
dirty
here,
here
I'm
i'm
going
going
to
to
use
use
touched.
touched
Action.
action
The
the
form
form
input
input
is
is
considered
considered
touched
touched
when
when
the
the
user
user
has
has
entered
entered
their
their
mouse
mouse
inside
inside
of
of
that
that
form
form
input.
input
So
so
that
that
just
just
gives
gives
you
you
another
another
option
option
for
for
determining
determining
when
when
you
you
want
want
to
to
actually
actually
display
display
the
the
error
error
message.
message
App.
app
We
we
can
can
also
also
tell
tell
when
when
a
a
form
form
is
is
valid.
valid
By
by
calling
calling
sign
sign
up
up
form
form
valid,
valid
we
we
can
can
determine
determine
if
if
the
the
entire
entire
form
form
is
is
valid
valid
as
as
well
well
as
as
all
all
of
of
the
the
inputs
inputs
contained
contained
inside
inside
of
of
it.
it
App.
app
As
as
a
a
final
final
touch,
touch
we'll
we'll
disable
disable
the
the
submit
submit
button
button
so
so
the
the
user
user
can't
can't
accidentally
accidentally
submit
submit
an
an
invalid
invalid
form.
form
When
when
the
the
user
user
submits
submits
their
their
form
form
and
and
they're
they're
successfully
successfully
authenticated,
authenticated
app.
app
It's
it's
going
going
to
to
hide
hide
this
this
initial
initial
form
form
and
and
then
then
bring
bring
up
up
our
our
secondary
secondary
form
form
here.
here
So
so
for
for
this
this
one,
one
we'll
we'll
bind
bind
it
it
to
to
the
the
set
set
catchphrase
catchphrase
method
method
app.
app
And
and
then
then
we'll
we'll
go
go
ahead
ahead
and
and
add
add
the
the
FormControl
formcontrol
name
name
and
and
then
then
another
another
submit
submit
button
button
for
for
that
that
as
as
well.
well
The
the
end
end
result
result
looks
looks
something
something
like
like
this.
this
App.
app
We
we
start
start
typing
typing
in
in
the
the
form
form
and
and
then
then
we
we
get
get
this
this
validation
validation
error
error
until
until
we
we
actually
actually
enter
enter
a
a
valid
valid
email
email
then
then
it
it
has
has
the
the
green
green
border.
border
App.
app
Then
then
we
we
go
go
ahead
ahead
and
and
enter
enter
our
our
password
password
and
and
we
we
get
get
the
the
green
green
message
message
that
that
the
the
form
form
looks
looks
good.
good
So
so
now
now
we
we
authenticate
authenticate
in
in
Firebase
firebase
and
and
then
then
it
it
brings
brings
up
up
the
the
secondary
secondary
form.
form
App.
app
The
the
sign
sign
up
up
process
process
works
works
as
as
expected
expected
at
at
this
this
point,
point
but
but
we
we
still
still
want
want
to
to
set
set
up
up
a
a
router
router
guard
guard
to
to
prevent
prevent
our
our
users
users
from
from
navigating
navigating
away
away
from
from
the
the
form
form
if
if
they
they
haven't
haven't
fully
fully
completed
completed
it.
it
App.
app
We
we
can
can
do
do
that
that
by
by
setting
setting
up
up
an
an
auth
auth
guard
guard
that
that
we'll
we'll
use
use
in
in
our
our
app
app
routing
routing
module.
module
Guards
guards
use
use
the
the
injectable
injectable
decorator,
decorator
so
so
they
they
behave
behave
just
just
like
like
services
services
do
do
in
in
Angular.
angular
App.
app
First,
first
I'm
i'm
going
going
to
to
import
import
it
it
into
into
the
the
module
module
and
and
then
then
add
add
it
it
to
to
the
the
provider's
provider's
array.
array
Then
then
you
you
can
can
use
use
the
the
guard
guard
on
on
individual
individual
routes
routes
by
by
setting
setting
the
the
can
can
activate
activate
property,
property
and
and
you
you
just
just
pass
pass
it
it
to
to
its
its
array
array
of
of
guards.
guards
Now
now
we
we
can
can
go
go
into
into
the
the
actual
actual
auth
auth
guard
guard
file,
file
app.
app
And
and
we're
we're
going
going
to
to
import
import
our
our
auth
auth
service.
service
And
and
if
if
you
you
remember
remember
from
from
earlier,
earlier
our
our
auth
auth
service
service
provides
provides
a
a
user
user
observable.
observable
So
so
what
what
we're
we're
going
going
to
to
do
do
is
is
convert
convert
app.
app
That
that
user
user
observable
observable
into
into
a
a
boolean
boolean
that's
that's
going
going
to
to
determine
determine
whether
whether
or
or
not
not
a
a
user
user
is
is
authorized
authorized
to
to
visit
visit
a
a
certain
certain
route.
route
App.
app
So
so
we're
we're
going
going
to
to
inject
inject
the
the
auth
auth
service
service
in
in
the
the
constructor,
constructor
and
and
then
then
we're
we're
going
going
to
to
use
use
the
the
Angular
angular
router
router
as
as
well
well
as
as
that
that
notification
notification
service
service
that
that
I
i
was
was
talking
talking
about
about
earlier.
earlier
App.
app
The
the
CanActivate
canactivate
method
method
inside
inside
the
the
guard
guard
needs
needs
to
to
return
return
a
a
Boolean
boolean
Observable.
observable
So
so
we
we
first
first
take
take
our
our
User
user
Observable
observable
and
and
then
then
we
we
map
map
it
it
down
down
to
to
a
a
Boolean,
boolean
app.
app
And
and
we
we
determine
determine
this
this
Boolean
boolean
by
by
whether
whether
or
or
not
not
the
the
user
user
has
has
that
that
catch
catch
phrase
phrase
property
property
on
on
their
their
user
user
document.
document
We
we
convert
convert
the
the
property
property
to
to
a
a
Boolean
boolean
by
by
adding
adding
a
a
double
double
bang
bang
in
in
front
front
of
of
it.
it
App.
app
If
if
this
this
evaluates
evaluates
to
to
false,
false
we're
we're
going
going
to
to
use
use
the
the
router
router
as
as
well
well
as
as
the
the
notification
notification
service
service
to
to
redirect
redirect
the
the
user
user
back
back
to
to
the
the
form
form
and
and
then
then
show
show
them
them
an
an
error
error
message.
message
App.
app
The
the
end
end
result
result
is
is
that
that
any
any
routes
routes
that
that
have
have
this
this
guard
guard
applied
applied
to
to
it
it
will
will
not
not
be
be
activated
activated
unless
unless
the
the
user
user
has
has
that
that
catch
catch
phrase
phrase
property
property
on
on
their
their
document
document
in
in
Firestore.
firestore
App.
app
That's
that's
only
only
going
going
to
to
secure
secure
routes
routes
on
on
the
the
front
front
end.
end
If
if
you
you
have
have
truly
truly
sensitive
sensitive
information
information
there,
there
you'll
you'll
want
want
to
to
also
also
send
send
a
a
back
back
end
end
database
database
rule.
rule
App.
app
In
in
this
this
case,
case
you
you
can
can
check
check
if
if
the
the
catch
catch
phrase
phrase
exists
exists
on
on
the
the
current
current
user's
user's
document
document
by
by
pointing
pointing
to
to
the
the
user
user
document
document
with
with
the
the
request
request
auth
auth
UID.
uid
ID.
id
If
if
it's
it's
not
not
there,
there
the
the
user
user
won't
won't
be
be
able
able
to
to
read
read
or
or
write
write
any
any
documents
documents
associated
associated
with
with
this
this
rule.
rule
That's
that's
it
it
app.
app
For
for
multistep
multistep
authentication
authentication
with
with
Firebase,
firebase
if
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
subscribe.
subscribe
And
and
if
if
you
you
wanna
wanna
learn
learn
more,
more
consider
consider
becoming
becoming
a
a
pro
pro
member
member
at
at
angularfirebase.com.
angularfirebase.com
You
you
You'll
you'll
get
get
a
a
free
free
copy
copy
of
of
my
my
book
book
as
as
well
well
as
as
1
1
on
on
1
1
project
project
support.
support
Thanks
thanks
for
for
watching,
watching
and
and
I'll
i'll
see
see
you
you
soon.
soon
App.
app
success
The speaker explains a multi-step sign-up process for developers to use in an app, including setting up an interface, email addresses, and creating a new user. They also provide instructions on setting up a router guard and creating a new user form. The process involves setting up a new user and updating data on a user document, and setting up a new form and validating user data. The speaker also discusses setting up a router guard and creating a web page for users to access a specific route, and mentions a free book and support page for the video.
Multi-Step Password Auth with Firebase and Reactive Forms
Firebase makes basic user authentication very easy, but what happens if you require additional data from your user before they're authorized to start using your app. In this episode, I'm going to set up a multi step sign up form that requires the user to fill out a catchphrase on their user profile before they're authorized to start using the app. App. Then we're going to secure all the application data on both the front end and the back end. This feature works by setting up a custom user document in the Firestore database. We can then verify that the current user has the correct information on their document before they're authorized to perform certain actions. In order to build this feature, app. I'm going to be using the Firestarter demo app, which is on GitHub. You can clone it if you want, but this code can be applied to any Angular app that's using Firebase. App. Before we get started, make sure to subscribe, and you can find all the source code at angularfirebase.com. The first place we're going to start is in the auth service, app. And in my case, it's in the core module. The goal of the service is to keep track of the current user and give them the ability to sign in via email and password. App. The important imports to take note of here are AngularFire auth and AngularFirestore as well as the switch map operator from RxJS. App. The first thing I'm going to do is set up an interface to model our user data. We need to have a user ID and email address, which we'll get from Firebase auth, and then our custom piece of data is the catchphrase. Notice that you don't need to actually add the password to the user interface. That's all handled by AngularFire auth. App. So our actual user is going to be an observable type to this interface, then we'll inject our dependencies in the constructor. The notify service that I'm adding here is part of the demo app. App. It's not required, but it's used to show the end user any problems with the sign in process. Then inside the constructor, we'll define the user variable. App. So we do this by calling AngularFireAuthState, which gives us an observable that we can call switch map on. If the current user is logged in, app. Then we'll go ahead and retrieve the user data from Firestore. We do that by calling a f s doc and then point to that current user's user ID app and then call value changes to get the observable. If the user is not logged in, then we're just going to return an observable of null. App. That chunk of code is going to keep track of the current user at the global level throughout our application. It's easy for things to go wrong with email password auth. For example, the user might try to log in end with an email address that's already been taken. When that happens, we're going to use this helper method to notify the user in the front end. After that, We're going to create another helper method that will create a new user document when the user first signs up. When the user signs up, Firebase will give us a user object. App. We can then use that object to point to a document in Firestore. At this point, we're only gonna have the user's email address and user ID, so we'll go ahead and set that to an object. App. Then we can update the document in Firestore. Now we need a way to create a new user by having them log in with an email address and a password. App. So we'll create a method that will handle this data and then we can call AngularFire auth create user with email and password. App. This is going to return a Promise and if it's successful, it will return the user object. And then we'll go ahead and use that user object app to create the user document in that helper method that we just defined. And lastly, we'll catch any errors and notify the user if there's any problem with the sign up. App. That handles the first part of the sign up, but if you have additional steps, you'll need a method to update data on that user document. App. This method will take the current user as well as the data that we wanna update, and then we'll point to that user's user ID in Firestore and update the data. App. Now let's jump over to the user form component and put the service to use. 1st, I wanna show you how it's set up in the router. So here I'm in the app routing module, app. And I have 3 unrelated components that we're going to lock down for unauthorized users later. And then our user form component, we're going to load at the login path. App. We're going to come back here a little bit later to add a router guard to secure all of these routes. Then you'll also need to go into whichever NG module uses this component app and import the Reactive Forms module from Angular forms. Now we can start writing this component. First, we need the auth service, app. And we also need a few reactive forms pieces, including form group, form builder, and validators. The component is going to use 2 separate form groups. App. So the first form will be the sign up form, and the second form will be the detail form where we collect any additional information we want from the user. In this case, we're only collecting the catchphrase property, but you could collect any information you want there. Then we'll inject Form Builder in the constructor as well as the auth service. App. To create a reactive form, you call form builder group, and then you pass it an object where each key is a corresponding form field. So in this case, we have an email input. Then app. Then we set its value equal to an array where the first value in that array is an empty string, and then the second value is another array of validators. App. These validators are based on their HTML counterparts. In this case, we are going to validate the email as required and that it has an email format. App. For the password, we're going to use a regular expression, which just validates that there's at least one number present in the password string. And And then we're also gonna validate that it has a minimum length of 6 and a max length of 25. Then we'll set up the second form in exactly the same way, but it's actually much assembler. We'll just say detail form is the Form Builder group, and its only field is going to be the catch phrase, which is required. App. And that's all it takes to set up a reactive form. It's just a series of form fields that are defined directly in your TypeScript. The main problem is that they generally create a lot of TypeScript code. So we can cut down on this code at least a little bit by using getters. So we'll call sign up form get email, app. And we'll repeat this pattern for each individual form field. When we get to the actual form HTML, you'll see that this drastically cuts down on the amount of code that we need to use in the template. The last thing we need is an event handler for when these forms are submitted. So when they submit the sign form, we'll call our email sign up method from the service with their email value and password value. And for the catch phrase, we simply call the auth service update user method with the catch phrase that they enter into that form. Now we're going to switch over to the HTML, and I'll show you how to use this reactive form in the template. App. I'm going to set up an NG container that's going to wrap both of the forms. The reason for this is that we can unwrap the user observable to apply some conditional logic to determine which form to show. So we'll do that by calling auth user async or we're going to show an empty object if the user is null. And then we're gonna set that to the user template variable. App. I realize that looks kind of weird, but it is a very useful technique in Angular. The next thing we'll do is set up our form group. App. So we do that by calling form group with our sign up form. This form should only be shown if we don't have a user ID, meaning the user has no Firebase account at all. App. Then I'm going to add the detail form right below it, and we're only gonna show this form if the user is authenticated, but they still don't have the catch phrase on their user document. App. Then I'll set up one more block here, and this one will show if the user is logged in and they have a catch phrase, meaning the form is 100% complete. App. You could extract this into separate components, but I'm just showing it all in one go here just to keep this as simple as possible. Going back to the sign up form, we'll app. First, find our sign up method to the NG submit event. Then we'll set a label and a form input for the email address. App. We connect this input to our reactive form in the TypeScript by calling form control name followed by email. Because we set validators on this form, we can determine whether or app. It is in a valid state based on the user's input. When the form is not valid, we want to show an error message, and we only wanna show it if the form is dirty, app, which means that the user has started typing into that Form Input. Then we'll go and do the same exact thing for the password, but the only difference instead of dirty here, I'm going to use touched. Action. The form input is considered touched when the user has entered their mouse inside of that form input. So that just gives you another option for determining when you want to actually display the error message. App. We can also tell when a form is valid. By calling sign up form valid, we can determine if the entire form is valid as well as all of the inputs contained inside of it. App. As a final touch, we'll disable the submit button so the user can't accidentally submit an invalid form. When the user submits their form and they're successfully authenticated, app. It's going to hide this initial form and then bring up our secondary form here. So for this one, we'll bind it to the set catchphrase method app. And then we'll go ahead and add the FormControl name and then another submit button for that as well. The end result looks something like this. App. We start typing in the form and then we get this validation error until we actually enter a valid email then it has the green border. App. Then we go ahead and enter our password and we get the green message that the form looks good. So now we authenticate in Firebase and then it brings up the secondary form. App. The sign up process works as expected at this point, but we still want to set up a router guard to prevent our users from navigating away from the form if they haven't fully completed it. App. We can do that by setting up an auth guard that we'll use in our app routing module. Guards use the injectable decorator, so they behave just like services do in Angular. App. First, I'm going to import it into the module and then add it to the provider's array. Then you can use the guard on individual routes by setting the can activate property, and you just pass it to its array of guards. Now we can go into the actual auth guard file, app. And we're going to import our auth service. And if you remember from earlier, our auth service provides a user observable. So what we're going to do is convert app. That user observable into a boolean that's going to determine whether or not a user is authorized to visit a certain route. App. So we're going to inject the auth service in the constructor, and then we're going to use the Angular router as well as that notification service that I was talking about earlier. App. The CanActivate method inside the guard needs to return a Boolean Observable. So we first take our User Observable and then we map it down to a Boolean, app. And we determine this Boolean by whether or not the user has that catch phrase property on their user document. We convert the property to a Boolean by adding a double bang in front of it. App. If this evaluates to false, we're going to use the router as well as the notification service to redirect the user back to the form and then show them an error message. App. The end result is that any routes that have this guard applied to it will not be activated unless the user has that catch phrase property on their document in Firestore. App. That's only going to secure routes on the front end. If you have truly sensitive information there, you'll want to also send a back end database rule. App. In this case, you can check if the catch phrase exists on the current user's document by pointing to the user document with the request auth UID. ID. If it's not there, the user won't be able to read or write any documents associated with this rule. That's it app. For multistep authentication with Firebase, if this video helped you, please like and subscribe. And if you wanna learn more, consider becoming a pro member at angularfirebase.com. You You'll get a free copy of my book as well as 1 on 1 project support. Thanks for watching, and I'll see you soon. App.
The speaker explains a multi-step sign-up process for developers to use in an app, including setting up an interface, email addresses, and creating a new user. They also provide instructions on setting up a router guard and creating a new user form. The process involves setting up a new user and updating data on a user document, and setting up a new form and validating user data. The speaker also discusses setting up a router guard and creating a web page for users to access a specific route, and mentions a free book and support page for the video.