Build a Fullstack App with Vanilla JS and Go

Adding Authentication Storage

Maximiliano Firtman
Independent Consultant
Build a Fullstack App with Vanilla JS and Go

Lesson Description

The "Adding Authentication Storage" Lesson is part of the full, Build a Fullstack App with Vanilla JS and Go course featured in this preview video. Here's what you'd learn in this lesson:

Maximiliano explains the process of adding a dependency for hashing passwords using bcrypt. He also outlines the steps involved in creating an account management system, including setting up model repositories, handlers for web services like registration and authentication, and corresponding components on the client side.

Preview
Close

Transcript from the "Adding Authentication Storage" Lesson

[00:00:00]
>> Maximiliano Firtman: The first thing that we need is we need to on the back end, we need to add a dependency, okay, so we will use bcrypt is the most common one that will have the hash functions to quickly hash a password, okay. Because doing that manually doesn't make any sense.

[00:00:17]
So I need to go here now we probably need to, I can stop the server. Remember, we are using, in this case, you can see all those messages are coming from our logo. I can control C, or I can open a new terminal, whatever, and I will get that particular library.

[00:00:36]
It's actually pretty quick. Xan because I already have it in my computer, but at least now it's in my go.mod. So there so I can start using it.
>> Maximiliano Firtman: So the next step will be actually to add the newest storage is, let's remember what we have. In fact, let's go back to our architecture to see where we are.

[00:01:08]
So now, actually we have fully created the diagram, because now we have the API service client side, the routers, the router, the web components. The user interface that shows the front end is full, yeah, there are still some more services to add, and the back end is also ready.

[00:01:28]
So now we have the full circuit for movies. Now we need to add the full circuit for accounts, account management. So we need the model. We need a model repository. Remember, the model repository is the one the storage that is actually talking to the table. The tables are already there.

[00:01:49]
But we need the repository. The model, I think, is already there, it's actually pretty simple, just the model user. Then we need the handlers for every web service that we will use. At least we need two web services, registration and authentication, also known as logging, okay, register and logging.

[00:02:09]
We need two handlers that will handle that, talking to the repository. And then we will need to add the same thing on the client side, so we will need the web component for each page, for the registration form, for the login form, the routes, then we will also need the HTML.

[00:02:30]
I don't know what happened, yeah, okay. So let's start on the backend first, and then when the backend is ready, we will move to the frontend, okay? Let's start with the model repository. So to do that, it's a huge storage actually. It's not complicated, but brightening from scratch, it may take an hour or so.

[00:03:00]
Okay, for registration and logging, mostly if you want to do it right. So because for example, registration, you need to validate that the data is coming. You need to validate that the email is valid. Then you don't want to register the same user twice. So you need to check, make a query and see if the user is already in the system and reject registration and then you need to hash the password and then start.

[00:03:30]
Well, all of that, it's already there, we will analyze it, okay. But if you remember from before as well we created in our back end, this idea of making the storage agnostic, so in the future, we may wanna change the database. So that's why we had an interface, remember.

[00:03:53]
By the way, I have just realized that I have a typo here in the name, and just for fun. Will it make any difference defining in Go? No, really, so that's why it never came until right now to my brain that I have a typo. It says interfaces, like interfaces, it's not gonna make any difference, okay?

[00:04:18]
Because the Go works actually, with the package name, okay? And then with the things that you are exporting with capital letters the file name, it doesn't matter, okay, so we have movie storage. So actually we need to create now the the other part that we can call account storage, that we can also make like an interface, yes.

[00:04:48]
>> Student 1: Back to packages, really quick, are there any names facing issues, like can you call a package go, for example, or is that can you not do that?
>> Maximiliano Firtman: There are, there are some names that are keywords, as in any language. But actually for the package name, I don't think I haven't tried to use Go, I don't think you have a problem to use Go, so you could use Go.

[00:05:10]
I don't see why not, because Go is not really, actually, Go is a keyword that you use for go routines to use concurrency. But I don't think it's gonna mess with the package name, I'm not sure, to be honest. I'm not sure why do you wanna do that, okay?

[00:05:30]
Anyway, but maybe because you wanna push the limits, which is fine. But, yeah, I don't see a use case for using go as a package name, but you should be able to do that. So what I want here, I want one definition for each service that I need from the database, okay?

[00:05:52]
And then we implement that, right now with PostgreSQL, but remember that we can change that later with other database. We have them here, it's not a big deal. I mean, I can write them or copy and paste them. It's not really a big deal. So, we have authentication.

[00:06:08]
Authenticate that receives true strings, email and password, then registration that has three strings because it's right now we have only name, email and password. Get account details that we may use later and save collection that we may use later. What is site collection? Save a favorite or save a watch list.

[00:06:33]
Okay, that receives a user and in the we'll see the the arguments later. I'm getting an error here with models because, actually, we don't have the user. It seems like if I go into models, I don't have the user model. So I need to create the user model.

[00:06:50]
So let's add it, so we need user.go. This is package models, and this is going to be pretty simple, similar to this one, so not really a big deal. So type user, okay, it's a structure, and then we have an ID integer. It's a good idea to always, as we did with movies, to add the meta data.

[00:07:17]
Remember, we use backtick, then we use JSON colon, and the name that in this case we use in the database and in JSON. So, what's called ID, then we have name, string, JSON name, and by the way, do a spot any problems with that name? In fact, VS code is finding a problem.

[00:07:41]
There is a warning here saying, hey.
>> Student 1: Not exported.
>> Maximiliano Firtman: Not exported, so use N. That's why we are renaming this here, because maybe in the JSON we don't have the name. If you don't do that, it will work, but it will expect the database and the output JSON to use N.

[00:08:02]
We have email.
>> Maximiliano Firtman: And password, but remember, the password is not just a password, it's a hash password. It's just, I mean, doesn't matter for the name. Actually we can say password. Let's stay with password only. I'll explain why in a minute. Because maybe in the model, we don't know if it's still hash or not, so maybe initially it's not hash, and then we hash it.

[00:08:30]
It doesn't matter, okay, so that's the user. So now my interface works. So interface is pretty good. Also, it lets us quickly understand what we need and what we're expecting from the implementation. So for the implementation, we are going to create an account repository. So I have a movie repository.

[00:08:53]
I need to create an account repository. You can also call it repository, user repository. And this is the one that is huge, to be honest, not extremely complicated, but huge, you can see, okay, a lot of work. It will take an hour or maybe so to do it from zero.

[00:09:19]
So I will just take it there, paste it. Maybe we need to solve some problems or names that are different or things like that, and then we will analyze it, okay? So let me first go through the errors. Yeah, I was expecting password so I change that, okay, password, that's one issue.

[00:09:43]
Then user, I didn't create the favorites and I didn't create the collection, yes, where in my model, okay? So what's this type of dose? What do you think? It's movies.
>> Student 2: Is it Boolean?
>> Maximiliano Firtman: Is it Boolean? First, it should be a collection.
>> Student 3: It should be a list of movies, okay.

[00:10:09]
>> Maximiliano Firtman: So list, yeah, we need to decide if we want to use directly like this or use IDs, okay? We'll see, we will do this at the end. So, but it's a watch list, but let's say, but from a semantic point of view, it's a slice of movies.

[00:10:28]
The slice is just an array with a dynamic size, okay, we don't know how many, that's why it's a slice. Okay, so now I'm, I don't have any errors. I have a warning there on that string that it has to do with the logging, doesn't matter. So now let's analyze the code.

[00:10:47]
But you will see it's simple to follow, but it takes a lot of time to write from scratch, I know because I wrote it. So first, we do have a structure. Why the structure is not mandatory, but it's a way to create some kind of an object. So create this, we are creating this account repository as if it were an object in other language.

[00:11:10]
It's not mandatory, okay? I could just create functions from the package. That are not methods of this structure and it will work anyway. I'm saving the database and the logger, why? Well, the database is straightforward. We need the database to talk to the database. We don't want every repository to initialize the database.

[00:11:30]
We are just reusing the same database connection. And the logger is to have always a pointer to that util function that I have to log my errors, log my information, so then I can go and see if something wrong has happened, okay. This is the constructor, remember, we don't have constructors in Go.

[00:11:51]
This is a factory, this is how you will create a new account repository, receiving the database and the logger. This is a normal pattern in Go. And then we start with the methods, methods of account repository. So register, that's the first one. It receives email, name, email and password as a string and returns a bool and an error.

[00:12:12]
So the bool will be, it's okay, or it's not okay. Okay, that's kind of the idea for now. First, we are validating basic requirements. There are a lot of other things to do here to be honest, this is a very basic requirement. I'm just checking that, I do have some data, but I should check if the email looks like an email, if the name has a minimum size and so on, okay.

[00:12:37]
So there are still more things to do here, but I wanna keep this course within size, like a proper size. So let's add more validation. So if we are not passing the validation, look at this, I'm creating, this is a pretty common way. I'm creating different constants for different errors, so then I know exactly which error has happened.

[00:13:04]
So in this case, I'm returning with false, so that bool, so I'm saying, No, we couldn't register the user. And this is the error. These errors, that are actually at the bottom of the file. That's a pretty common pattern where I'm creating all these variables for all the possible errors that I might trigger, okay.

[00:13:27]
So going back, I'm sorry, because I'm scrolling a lot here. It's a long file. So then I will check if the user already exists by email, that's our key here, okay? So I'm making a query, and I'm selecting if I have one user at least with that email, and if it already exists, I'm sending a message saying, hey, already exists.

[00:13:53]
Also we can have generic error because maybe I couldn't make a query. The database is complaining that in that case it's a generic error. I'm actually sending the error that I'm getting from the database. It's not my error, okay. Then I'm hashing the password, actually, it's pretty simple to hash the password when you're using a library.

[00:14:14]
We call to that, we call that Bcrypt library. That's the one that we added in our project. We generate the hash from a password. We pass the password instead of a string. We need to pass bytes. So that's how you would call one of these conversion functions to a slice of byte.

[00:14:32]
And we use some options, so there are some options that you can define here in terms of cost, default, max or min. This is the CPU cycles that you will use to make a more like complicated hash or a simpler hash, okay, something like that. And well, if we fail, we do this.

[00:14:50]
Of course, we can do this quicker, just by removing all these ifs the premise that if we do that, okay. If something goes wrong, we will miss the moment of what happened, and we will miss the opportunity to log the problem and debug the problem, okay? So that's why, when you have things like registration or user authentication, it's really long because we actually really wanna spot on every possible problem.

[00:15:19]
And I'm saying every as kind of a dream, at least as much problems as possible, because there are always more problems that may arise that we didn't consider, okay. Well, if everything is okay, we are going to try to insert the new user, okay, and of course, the database can complain, so maybe it's not inserting that.

[00:15:43]
Finally, if everything is okay, we will return true and nil as an error, only on that situation if we reach the end.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now