Creating a User Signup Flow for a Multi Tenant Svelte App

User Registration

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Fullstack Svelte course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Fullstack Svelte, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Fullstack Svelte

Hello and welcome back. We are going to work on user registration in this lesson. In the previous two lessons, we worked with Auth0 users, but we created them manually in the Auth0 dashboard. Now we are going to work on a way for users of our application to self register for the app. Additionally, since we have a multi-tenant architecture now, we're going to prepare a database for each new user/school. When they register a user account, they'll also provide information about their school and will create their database at that time. There's going to be two parts. We're going to do an Auth0 part. We're going to do a process where the user in our Svelte frontend calls an endpoint in our express backend. Then that endpoint in our express backend will make a machine-to-machine call to the Auth0 management API. Then a second part will have our next migration create a new database and migrate it to the latest state. The reason we need to go from our frontend to our backend to Auth0 is that way we can keep our secrets for our Auth0, our API key, only on the backend. Otherwise, we have to send our secrets down to the front end and we don't want to do that. This type of approach is called a proxy approach. We're going to proxy a request from our frontend through our backend and then to Auth0. Here's the overall plan. We're going to finish building the user registration form in our home page. We started it and we're going to finish that. We're going to set up a machine-to-machine application in Auth0. Then in home.Svelte, we're going to make a new call to a new post-users endpoint in our express backend. Then from that express post-users endpoint will create the user and if that successful will create the database for that school. Auth0 machine-to-machine applications . So far our frontend has been integrated with Auth0 but if we want to use the Auth0 management API then we're going to set up a machine-to-machine application and this will allow our backend to interact with Auth0 and this allows us to protect our secrets. Any frontend JavaScript run by the browser can be read by any user and so we never want to share secrets, tokens, etc. in the frontend. Head over to Auth0 dashboard and navigate to the applications section and we'll create another application there. So applications create application, machine-to-machine application and we'll call it school lunch backend. And then select the Auth0 management API and then we're going to grant create users and create users app metadata. Those are the two things we're going to want to be able to do through this API and this just allows us to grant only the things we need so we 're not going to give this application any more permissions than what it needs for its base functions . So create users, create users app metadata and then hit authorize. Okay and so we're going to start by working on our backend and we're going to actually use Axios in the backend to do the call to Auth0 so it's going to be real familiar and similar to what we're doing in our frontend and so that's one nice thing about JavaScript. Once you kind of learn these libraries you can use it in either the backend or the frontend. So let's go ahead and install Axios in the backend project. So stop the backend project if you already had it running. NPM install Axios. Then restart it NPM run nodemon. Okay and then we're going to be working in routes/users.js. So this file should already exist and we're going to clean it out and create a new endpoint there. So I'm going to copy this. So in the backend project go to routes and users.js. So this was kind of some test code we had earlier. We're going to get rid of all of that and just paste the new code in. Okay so in order to interact with the Auth0 backend we need to first get an Auth0 token and so we do this through this endpoint called OAuth token and that'll give us a token and then we can use that token to then make a secondary API call to do what we want to do which is going to be create a user. So this is just an intermediary step for right now make sure that we're having the first part of this working so we're just going to grab this token and then just send it back for right now. Okay and there are some new environment variables here so we're going to need a client secret and client ID and audience and issuer. Let's check here. So we've already got audience and issuer so I think we need two more. So let's go ahead and copy these in. So this is the .env file where we're storing our secrets now and then we'll go to Auth0 to grab these two bits of information. So this is our machine to machine school lunch backend. So go over to settings we need the client ID so copy that. Put that there and then we need the client secret. Copy that and put that there. Okay. All right so this is our post users endpoint and basically what we're going to do is fetch a token from Auth0 and then just return that back to a caller. So we can give this one to try and postman. So it's going to be a post and it's going to be api/users and this is actually going to be a public endpoint because we want users to be able to register and those users won't already have an account and they won't be authenticated so we don't need to worry about authorization for this call. And let's go ahead and hit the send button to test this. Okay good so we get our Auth0 token back as we specified here in our endpoint. So right there. Okay so what we're going to do next is now that we have that token we're going to use it to make a secondary call to Auth0's management API and post a user record. So we need to do a couple of things. First of all we're going to have a little helper function that will create a lowercase database name based on a proper case school name and we're going to replace any spaces with underscores. So this will be a little helper function we'll use for that. I'm going to paste that in. And then looking further here so inside our post endpoint we're going to read rec.body.school name called that helper function that'll give us the dd name and then we're going to build an object a user object that we're going to send to Auth0. So this user object here is going to look similar to if we look over at Auth0 and look at a user example and go to raw.json. So these are the properties that we can send in. So we're going to send just the minimum amount that we need to post a user. And so we're going to have email which we're going to pull from rec.body.email password we're going to pull from rec.body.password . Connection is going to be username password authentication so that's just statically coded in there . And then we're going to put the app metadata which is going to be the school name from the body and then the db name that we generate from our helper function. So once we have that we'll grab our token that we just saw works. We'll create some configuration for axios and we're going to put that token into an authorization bearer header. So that's what this part's going to do. And then we're going to actually make the axios request from our back end to the Auth0 API. And then we'll get the response back and send that back to the original caller. Okay, so let's paste this in. So that's going to go here. Do all of that stuff that we just talked about. And so we're ready to test this in postman. But we're going to need actual body this time. So we're going to need a JSON body. Let's go ahead and copy this into postman. And so we've got a password here. And off zero default password rules require a minimum of eight characters. And a mix of uppercase and lowercase letters and numbers or special characters. So you can't use a real week password. It'll fail if you try to do that. And so right now we're just testing a user post later on, we're going to let the user themselves specify the password when they're registering. But for now you can just use a dummy password something like this. Okay, so over in postman. Over to the body. This time we're going to actually need a body. And then we'll send this to our backend. Okay, so we get a 200 Okay back. And we get some information here back from Auth0. And right here you can see the app metadata. So our helper function translated that into lowercase, Westside underscore high. And we can just check over here in Auth0, go back to users. And there's our test user that we just created. So that seems to be all working there. Okay, so now we need to do another thing per our plan is that when we get a user registered through our endpoint, we're going to need to create a new database for that user, and migrate it to the latest DB schema to create the tables and columns that belong in it. So and then we're also going to need to register that database on catalog. schools table so that we have a record of it and we can maintain it over over time with our startup script. So let's go ahead and import next. And then we're going to create a create database function. So copy that part. Import next there. And then copy this part. Okay, so let's break this down a little bit. So we're going to get a next config. And first of all, we're going to start with the catalog. So the database is going to be catalog. And then with this next config, we're going to use our environment variables from our .env file. And we're going to create the new database. So this is going to be the database name that originated from the caller. So in our example, it's Westside underscore high. So that'll actually create their database. But then at that point, it's going to be empty. So then we're going to register that database in the schools table in the catalog. Then we're going to create a connection to the new database. And we're going to migrate it to latest. And so that'll bring it up to speed. And all of this is going to happen pretty fast. It is a few steps, but it's going to be pretty fast. And right now we don't have too many tables or schema changes. So I don't think it's going to be a big problem at the scale we're at right now. Okay, so that's our create database function. It's grayed out because we haven 't actually called it yet. And so we're going to call it. Inside our post endpoint. Let me just check. Yes, we're going to do it at towards the end after we've successfully created the user. Right before rest dot sin. So we're going to do it right in here. Okay. So we'll go ahead and test this again with Postman. And this time we'll check in PG admin and make sure that the new database was created and migrated. So let's see. I'm going to change this to Eastside. Change this around a little bit. Okay, go ahead and send that. Okay, so looks like it happened pretty quick. We got our okay response back. And let's head over to PG admin. Refresh this. And so there you can see we got our Eastside high database. And it's got all the tables in it that we need. So it looks like everything's working pretty good with that flow there. Okay, so back end parts working good. And we 're ready to work on our front end registration form. So much earlier in the course, we created a kind of a quick and dirty registration form in home dot spelled. And we're going to improve that form and actually wire it up now. So let's take a look here. Back here at home. So this is the form we're talking about. So we've got email address and school name there. And it doesn't actually do anything when we hit go it just alerts. Okay, so here's what we're going to do to get this part working. We're going to actually have two steps. So step one is going to show these two fields. And then step two, we're going to have a transition and we're going to get rid of these two fields and then show a password field and a confirmed password field. Okay, so we're going to need a step state variable. And we'll use that to control the user interface. And then we'll use spelt if blocks to hide the field in step one and step two. And then we're going to use a spelt fly transition to add some animation to the form. And then lastly, we 're going to have some Bulma validations, some text to make sure that the email is valid and that the password conforms to the op zero password standards. Okay, so let's go ahead and copy this into home.s felt on the front end. We get rid of what we've got now. So we're going to organize our form a little bit more. So we've got it in one object. So we've got our registration form object here. And go ahead and stub out a couple of functions here. And then we're going to add our if blocks. So if step equals one, then we'll show this set of fields else if step equals two, then we'll show this set of fields. And since we put everything underneath a registration form object, we need to add that right here. So previously, we just had email. Now we need to use registration form dot email. I'm going to copy that part over. Yeah, we changed it from email address to email. So shorten that to. And registration form dot school name. Okay. And then let's add our if blocks. So we'll have if step equals one. That's going to start right there. Let's see. Actually, I'm just going to paste all of this in to make it a little easier. And so one one other difference here that I should highlight is right now we have a go button. So we're going to change it on step one, we're going to have a next button. And it's going to call the function complete step one. And so then that complete step one function is going to set the step variable to two, which is then going to trigger the reactivity and show all of these step two fields. And then that one's going to say submit. And then on click, it's going to call the register function. Let's copy all of this and just make it a little easier. Okay, so I'm going to copy from here. Down to here, I think. Okay. Let me give this a try and see if that's working. Yeah, so when we hit the next button, now you can see the field switch to the two password fields. And the button switch is from a next button to submit. And then if you refresh the page, it'll restore the state. Okay, so we just tested that initial functionality and it seems to be working. And so you notice there is super quick. So spelt reacting so fast that it's hard for the user to even tell what happened. So we're going to use a fly transition to kind of make the user experience a little bit better. And you can click this link here, it'll take you to the sp elt docs on transitions. There's a lot of neat stuff you can do with that. So for our purposes, we're going to copy this import statement and import fly into this component. And then we're going to update the markup to use the fly transition. And so in order to do that, we just need to copy this block right here. So right here, what says password block. And this is this block is wrapping both of our password fields and our submit button. So it's going to apply to everything that it's wrapping there. And you can set some variables such as the x position and the duration of the transition. If you want to play with it a little bit, you can change that there . So let's give this a try now. So now when we hit next, we get a little transition kind of animation, it makes it a little neater. Okay. All right, so making a little bit of progress. And next, we're going to add email and password validation. And we're going to use a combination of spelt and boma for this. So boma has a nice approach for adding text above or below a form input with a simple class called help. And then we can use that class in combination with if blocks to dynamically show validation messages when they're needed. So we're going to need, we're going to use this email message and password message state variables. That's going to store the message and we can use those to control our if statements. So we already pasted them in. Go ahead and uncomment those. We're also going to have some check email and a check password validation functions. And so these are going to have red jacks is in them. Red jacks are used to check patterns. And it's going to make sure that the email that the user entered is a valid email with an at symbol and conforms to email standards. And then this password is going to make sure that the password is eight characters and contains a combination of uppercase, lowercase letters and numbers or special characters. So that's going to be one check on the password validation. And then secondly, we're going to check to see if the first password matches the confirmed password so that the two check to make sure that the two fields match. So let's copy these helper functions in. So what we want to do on complete set one step one is reset any previous messages. And then we're going to check to see if the email is valid because that's what specified in step one. And if it's not valid, then we'll set our email message and then just return. So we're going to return before we set step equal to two. Okay, so let's copy that. And then on the register function, we'll copy this and we're still not posting to the back end yet, but we'll deal with that in just a minute. Okay, so that's the script portion of this. And we're going to update the markup now. So we'll start with this example. So this is the email message part. And we're just going to show a p tag with the is danger classes. And then the email message, which we're going to set based on our validation function right here. So it's going to end up saying email address is invalid. And then similar, there's a couple of different password messages that we might show. Okay, so let's copy this email message cart, it's going to go right below the email address input. It's going to go right there. And then same thing for the password message. We're going to put it right below the confirm password field, which will be the bottom one there. Okay, so let's give this a try. So on step one, if I were to enter just test here, and hit next, it's going to fail the validation, which is going to set the email message variable, and then spelt is going to reactively put it on the UI. So this is going to return true, because it's populated with something that's not faulty. And it's going to show this tag with the email message populated. And so all of that is based on our helper function here, returning a little object that says valid faults, and then provides the message . And then we assign those two right here, and set our state, which kind of triggers the whole chain of events that we want to happen in spell. So let's say test at test.com. That'll allow us to be a pass there. Now if I enter a short password, it submit , I'm going to get a message that my password is too weak. So that's one of our conditions. And I can also, if I do passwords that don't match. So first check is going to be that. So I have a complicated password, but something that doesn't match. Let's see. So I need to pass this first regex, I need an uppercase character. And then something that doesn't match that. There we go. So there is a condition where I've got a strong password that complies with the requirements, but then my second confirmation of that password doesn't match. So under that case, we'll show this message. Okay, so the front end form is looking pretty good. Let's continue with posting to the back end. So we're going to add a loading flag and some messages, and then we'll post to the back end with Axios. And what we're going to do once we get a successful response from the back end, we'll redirect the user to one of our admin components, and then that will redirect them to op zero, and they can log in and then they'll come back to our app. Get started by importing Axios into, let's see, let's import Axios and icon and refresh. We'll import all of those into our home.svelte component here. And then we're going to have a little more state here. So we're going to have a registration error message, registration success message, and then a registration loading flag that will control a spinner with. Okay, so let's put this into our register function. So we've already got the password message part. So we need this try catch piece here. use the registration Okay, so we're using an await here, so we need to make this async. And so if we pass our validation, we'll get down to this try block, we'll set registration form. That'll be this object here, everything will be bound from the inputs already into this form. So we don't need to do anything special there. And then we'll toggle registration loading to false. And then what we're going to do is show a success message, we'll say thank you for registering, redirecting to login, and then we'll just do a little sleep. So we'll just sleep for 1.8 seconds. And then we'll do the redirect. Now if we have an error, we'll fall into this catch block, and we'll show the error from the server. Okay, so we need to do a little bit more in the markup here. So let's see, we're going to put this right above the submit button. So we need these three blocks here. And it's going to look like this when it's done. So down here, here's our submit button. And we're going to put these three if blocks there. So if registration loading, we'll show the spinner icon. If registration error message, we're going to show a div with a warning style. So it's going to be yellow. And then if registration success, we'll show a div with an info style. So that 'll be blue. Okay. And we wired up to post to the back end inside our register function. So when they hit the submit button, we'll call register. And that'll do the post. All right, so let 's give that a try. Let's enter a test username. Okay, school name and then hit next and then enter the password twice. Now when we hit submit, we've got our post to the back end, we got our redirect ing message with a little timeout. And then now we're redirected to actually log in. So let's try that user out. Now this message, by the way, you can get rid of this also in the API controls, but it really only does it when you're on local host. So don't worry too much about this if you're worried about it. Okay, so we got logged in for the new school that was just registered. And let's check in Postgres here. So there's our JS school. So that worked there. Check the tables. So we've got our lunch day and lunch week table. So user was registered. They've got their own database and they're ready to go. And that finishes a big challenging module on security. So we did a ton of stuff. We started with JWT based security and just kind of having a baseline, securing the app with JSON web tokens. Then we evolved the whole app to a multi tenant architecture. And then lastly, we implemented user registration, where we proxy a request from our front end through our back end. And then over to the Auth zero API. And then we create a database for that user and then migrate the database to the latest schema. So we've made tons of progress. And at this point, we have a secure multi tenant full stack application. So if you've made it this far, congratulations, you've done a ton of great work. And you could kind of stop here. But for our school lunch use case, we still need a publicly viewable weekly lunch menu page . So we're going to tackle that in the next lesson. And that's going to be good bit easier than what we just did. And then lastly, we're going to do a couple of lessons on production deployment . So we'll show you how to run to deploy the app onto a cloud production environment. So thank you for making it this far and we'll look forward to seeing you next time.