Web Authentication APIs WebAuthn Server Endpoints
Transcript from the "WebAuthn Server Endpoints" Lesson
>> So now that you know this, we were doing this step-by-step. But now that you know this, every time you are starting a new project from now, you should start thinking about this flow. Identifier first, and then we continue with the process. So the next step is probably the hardest one in terms of coding, that is adding the endpoints for working with, let me go back here.
[00:00:33] We're going to add the endpoints for web authentication, okay? So, but it's a lot of code. So in this case, I think it's a good idea to maybe copy and paste this code, and then we will analyze what's inside, okay? I wrote this code, so I know what the code is doing.
[00:00:59] But it's a lot of steps, and some of the steps are kind of obscure, and at first, you don't understand what's going on. So it's simpler if we just put them in our server and then we analyze what's going on, okay? So how many endpoints are we going to add?
[00:01:17] Four, why four? Because we have two per flow, so we have some kind of spoke, salute two flow, okay, spoke solute. So why two? Because we have, first, registration and then we have authentication, the login. And for each flow, we always have two endpoints. We have one that is called get options or options, and the other one verification, both are doing the same thing, okay?
[00:01:50] So I'm going to take all my registration, these are the registration endpoints. So let me take these two first. We can try registration first and then we paste the other two. So I will put them here at the bottom, so let's say this is going to be WEBAUTHN ENDPOINT.
[00:02:12] Okay, I'm gonna paste first registration, okay? And let's try to analyze what's going on, the first one, registration-options. We're going to use these endpoint when we wanna register a new way, a new login mechanism for that user, okay? So first, we do that after we know who the user is.
[00:02:37] Somehow, because the user has typed that, or because it's already logged in, I don't know, okay? But we should know first who the user is, or how the user is identified in our system. So that's why I'm receiving the email and I'm finding that user, okay? So then we need to create an options object with some properties that are defined with these names in the WEBAUTHN spec, okay?
[00:03:07] So rpName, what's RP? Reliant Party. We are the Reliant Party, okay? So this is the name of our website, of our project. Then we need a Reliant Party ID that I think I have it defined at the top as a constant here, that tends to be your domain.
[00:03:31] So right now, it's localhost. Of course, if you deployed it somewhere else, you should change the Reliant Party ID, okay? Make sense? Let me go back here. So userID and userName. userName is the visible identifier, and the ID is the internal identifier for that user within my system.
[00:03:53] So in our system, it's email and name in our database. timeout is how much time we will wait for the user to finish the operation, okay? There are a couple of steps, the attestation, the authentication, it doesn't matter. So how much time I'm willing to wait for getting that authentication.
[00:04:16] attestationType, in case you wanna change this advanced part. So we will leave that for the advanced web application workshop later. So excludeCredentials, the idea is that we can pass an array of credentials that we already have because we are registering a new one. I don't want the user to have two face IDs over the same website because it doesn't make any sense.
[00:04:41] So I don't want the user to register two public and private keys over the same kind of authorization. Make sense? So that's why we are doing this, but we still don't understand what we're going to say, so you will understand this code in a second. But basically, for each user, we will have an array of devices.
[00:05:04] So this can be a device, okay, a USB key, this is a kind of UBECO compatible USB key. But it has a button, so that's why, because I need to interact with it, when I pull it, I will show you this in a minute. This can be another authenticator.
[00:05:19] Another device can be my face, my touch ID. So I can have more than one per user. So in terms of data storage, in terms of data structure, meaning if you are creating a database, like a SQL-based database, the relationship between user and devices or users authentication systems is one to one.
[00:05:46] So far, we have one user, one password, so it was just one table. But here, the user can be authenticated, the same user, with different mechanisms. So it's one to one, so that's why we have an array, okay? Then authenticatorSelection here, you can filter which type of authentication we're accepting.
[00:06:07] For example, if userVerification is required or not, okay? You can change that. To be honest, in the real world today, the real world is actually not the spec. But what browsers are supporting, it's not going to change too much if you say not require, actually. This is optional, so if you just remove this, it's gonna work, and it will take default values by default.
[00:06:32] And then I'm accepting two common algorithm. This has to do with the keys inside and the challenge, it doesn't matter. We typically send those two values, okay? If you wanna learn more about that, just take ES 256 and RS 256, and you will get more detail about what that means.
[00:06:53] But with that, just take these for granted. And then we don't take, this is a JSON object, so it's an object, okay? We don't send that object to the client yet. We need to some kind of wrap it, some kind of decorate that object through our library. So here I'm using the SimpleWebAuthnServer library, so we generate registration options based on my object.
[00:07:24] And it's going to return another object that it has more properties, and it has public keys, signatures, and it has the challenge. So the server will send a challenge to the client, okay? What I'm doing is I'm saving that challenge in my user. Why is that? Because this is two step process, later, we will verify that the challenge sent by the browser is actually the challenge we sent originally.
[00:08:05] So this is for verification and to avoid security issues. So I'm saving this in my database. Okay, makes sense? So this is the first endpoint. Again this endpoint is going to be executed. When the user express with a button, I wanna have face ID, or I wanna have web authentication, or I wanna have the passkey.
[00:08:30] In that case, we will trigger first this call with an email. Make sense? Do you have any questions on this endpoint? This point? No, so then I mean, with this object that we are passing to the client, we will request client side to the web authentication API an authentication, okay?
[00:08:58] Which is register an authentication. And the browser will give us an answer, and that answer will come here to the next endpoint that is called registration-verification. We're going here to verify that everything looks good and no one has changed the data in the middle, no man in the middle has added or changed my information.
[00:09:23] So in this case, we will find the user, and we will take the data that is sent by the API. And here, we are going to, among other things, verify the challenge, the expected challenge. So this is going to check if the data is exactly what we are expecting, okay?
[00:09:45] And if everything is correct, okay? If verified and we have all the information, well, we are creating a new object, a new device. Well, first, we check if the device already exists. If that's the case, it means that I already saved that touch ID for that user on this device, so I'm not going to save it twice.
[00:10:11] So I'm doing nothing, okay? And if it doesn't exist, I'm creating the newDevice object, and saving that to the user.devices array, okay? I mean, it looks like a lot of code, but at the end, it's not so difficult to follow, okay? The flow is we are at the beginning.
[00:10:33] We start analyzing the flow, it's kind of, what's going on here, okay? And then we say, okay, we saved it. And that finishes the registration operation. At least server-side. Okay, make sense? Do you have any question so far? Until we don't add the client cycle, it will still be kind of weird.
[00:10:59] Okay, so that's the registration. Then we have another pair of endpoints that actually they look pretty similar in terms of the code inside for authentication, which is actually login, okay? So let's say that now the user wants to log in with face ID or with a USB key.
[00:11:25] Okay, so in this case, we start with something similar. We create an options object that will have a challenge. And then we decorate, we wrap that object with the WebAuthnServer library. In this case, we generateAuthenticationOption and not generate registration option. It's a different function, okay? So internally, there are some differences, but the whole code looks pretty similar.
[00:11:55] So the flows are very similar. So in that case, we pass that to the client. The client will render a dialog, so the user can show her face or the user can put his finger. And then we will verify that information that we receive is exactly the same as the one that we have saved in our database.
[00:12:18] So here there are some buffer operations, because what are we going to save in our database? We will see this in action in a second. But are we going to save the information about the fingerprint from the user or the face details? No, we just save an identifier, like binary data that was signed that identifies that face for my website only.
[00:12:45] So the same face from the same user and the same device but on a different website, we have a completely different data. This is to avoid fingerprinting. By the way, there are libraries for web authentication for all the backend languages, for Go, for Java, for .NET, for Python.
[00:13:05] So no matter the language you have, there are libraries that will help you with authentication in the backend, okay? This is the simplest libraries I could get and the one that is more updated for Node.js.