Web Authentication APIs

Login with WebAuthn

Maximiliano Firtman

Maximiliano Firtman

Independent Consultant
Web Authentication APIs

Check out a free preview of the full Web Authentication APIs course

The "Login with WebAuthn" Lesson is part of the full, Web Authentication APIs course featured in this preview video. Here's what you'd learn in this lesson:

Max adds a link to the form to log in with WebAuthn or a passkey. This link will only appear if the user has added an authenticator to their account. Testing authentication flows in iOS, and the Chrome Dev Tools is also covered in this lesson.


Transcript from the "Login with WebAuthn" Lesson

>> So what do we need to do? Well, now that we have that, we need to show something here, somewhere. Saying, hey, use Touch ID or use your passkey or however you wanna say something there. Unfortunately, that UX part is still in discussion. We don't have, this is the UX you have to use.

I think that we are still finding the best user experience for web authentication. I think that we will go to the index.html then we'll read out the last change for today in the html. So in the login form here, we already have an empty section here for webauthn.

So here we can add a link, href with nothing, something like that. So it will pass validation. We will say that this is a navlink, you will see why later we use that. And well, maybe navlink here is used by the router to do things but anyway. I will say that onclick, I wanna call Auth.webAuthnLogin.

So we wanna log in with Web Authentication. And just because I'm here, I'm going to prevent default over event. I know it feels a little dirty but why I'm doing this? Because, It's a link and the link, if I have this hash, it will change a little bit the URL.

So it will call the router. We wanna do that, okay? So just for that. And we can say login with WebAuthn or with passkey or whatever, okay? This is the part that is still tricky to get right, okay? So we're going to log in the user with those options.

So we need to write the code for Auth.webAuthnLogin within our Auth option, okay? So it's going to be an async function and actually I mean, the process will be kind of similar to the previous one. But instead of calling the APIs for registration, we will call the APIs for authentication, okay?

Remember that we have these two flows and both are pretty similar. So what we need, I need to get the email from the form because these APIs will need the email. To log in the user we need the email because we are going to create options at the station on everything with the email address of that user.

It can be an ID, any way to identify the user will work. So I'm going to get an element by ID from the login, okay? And first I need to get the option from the server. So the first step in the flow. So I'm going to await for API.webAuthn.logInOptions that one receives the email, which is okay.

The next step is to call the API. So I'm going to now login or authenticate the API doesn't talk about login, it talks about authentication, okay? But because we were talking about login I'm continuing that wording. So I'm going to talk with my SimpleWebAuthnBrowser library and I'm going to startAuthentication, not registration but authentication.

Pass in the options received by the server, by our backend. By the way, it's known as the WebAuthn server. So our backend is now a WebAuthn server. It's possible to separate your WebAuthn server from your backend. It's possible to have a completely separate WebAuthn server, okay? That happens if you have really large amount of users validating at the same time, you can actually separate that.

But normally, it will be the same. And then we need to verify. So I'm going to wait for the verification response from my API. We don't need to pass any other arguments. Those arguments are okay. So we're going to verify the login result from the API, something like that.

The only that you need is the email, of course because it needs the email and the data. I think that's okay. So I tell you that will tell us if the login was successful or not. So this is our third way of login. We have login with username and password, login with Google and this is log in webAuthn.

So I will check if I'm sending an ok from the server. And if I'm sending an ok, I can call post login as with the other login methods, it needs a response. We can pass that response that we receive and a user. And we on the response, we will check that, let me check if that's the name.

But we pass a user. So let me go to the server for a second and this is the login verification. At the end, we are passing a user, okay? With name and email that is coming from the database after we logged in the user with a face or a USB key or whatever.

So that should be fine and if not, something has happened. So we are going to alert with verification Message. What could be wrong? Well, someone can be hijacking the webAuthn API or the data coming from the API. Or maybe you're in a different device, so your face is not the one register or for example I have here I register something with my MAC and it's not actually available in the iPad even if it's the same account.

But pass keys, they have a difference. And we will mention that in a minute. But pass keys is like one step over this. So pass keys are actually shared between devices. They are stored in the iCloud. Okay, so I think that's okay, let's see now. So if I try to log in again, now I can log in with other competition.

Look at that, I didn't press continue, it worked automatically and now I have the login with WebAuthn link. If I click here I'm receiving okay, it seems like there are some passkeys available for this. I'm not sure which one is the one that I use actually for localhost.

So let's try that one. Maybe it's not and if it's not I will get an error. Authenticator is not registered with that site. That wasn't the one. And by the way, it seems like it's, can you see that? So the event.preventDefault didn't work. So let's see why from my html.

event, I didn't curl preventDefault. That's why it didn't execute the function. That's why the router changes the page. So try again, let's see if I can find the one that I need. We refresh, m@m, login. Maybe Max. I don't know, if not I would create a new one but I can create more than one.

Yep, I'm logged in with Touch ID, so it worked. Now, go into Chrome. On Chrome, I can use the USB key. But it was for my Gmail, I think. I registered that for my Gmail. So continue. I don't have a password, look at that. No password, why? Because this account was federated, so I don't have a password.

So I can log in only with Google Or with webAuthn. So if I click here, I can use my finger, okay? Or I can go to other options and select USB key. And here it says, there are two. That's because it's localhost and it seems like you have more than one.

And it was that one and I'm logged in now. So it's working. I can try now this on my iOS simulator. Localhost.5050, so I can log in. m@m, I think I have another, I can register a new account. Let's get a new one. My name is iPhone. And it's iphone@mac.com and password, whatever.

Let's say, TimCook. Register account, I mean, I'm going to authenticator. So the only passkey, yes. Face ID, matching face. You can now log in. Okay, cool, iphone@mac. So let me log out. So now iphone@mac.com. I think I have, look at that, I have capital I. And in fact, that's something that we should improve for user experience.

Lowercase and trim my email addresses because an auto competition can actually change. You don't see that but let me, zoom in. It tried with Iphone with capital I and of course, it's not the same in the string. So there we are. Because let me see what's going on.

Let's try again. iPhone, by the way I can disable that also with a HTML Property. All right, let me write it correctly now. Well I would change it there. iphone@mac.com. I don't know why it's forcing me. You can also turn on the keyboard, that one instead of using your Mac.

I think it's my Mac keyboard that's for some reason is doing that uppercase I don't know why. Okay, so now it's giving me webAuthn. So if I try to login, also I have two, I think it's iPhone or I don't know which one it is. Well I can try.

That's because on this simulator, I try another example, continue, sorry. Now matching face and maybe that one, yep. Ang log in with Face ID. Do you have any question? You have a happy face. That's a happy face.
>> This is freaking rad.
>> [LAUGH]
>> Yeah, that's really cool.

>> So I know that this last part was more complicated to follow because webAuthn is complicated to follow. But after you implemented that, it starts to make sense, the process. Now, let me show you something else that is interesting is that if you're using Chrome, Chrome is offers us also a webAuthn emulator.

So instead of actually using a real USB key or using my real finger, I can simulate this, how? Well, Chrome dev tools, let me put this in fullscreen. Chrome DevTools have something known as the console drawer. Not sure if you have seen these before, the console drawer. Is when you press escape it appears a new menu.

And let me close everything here. And this, the console drawer also has tabs but the tabs are closed by default. So if you go to them that menu, not that one, not that one, okay? This one, the one from the console drawer, you have a lot of options.

And one is webAuthn. If you open that, you can enable a virtual authenticator environment. So if you do that, let me remove the ones that I have. I can create a new virtual authenticator. So it's like an emulator that generates the keys and everything but virtually. Then I can delete that and everything is gone.

You also need to delete that server side because if not you will keep private keys that you will never use again. So here I can select the internally which technologies do you wanna provide internal. So in this case, again it's not going to be internal or nfc, is how this is going to be announced to our server.

If it support user verification blah, blah, blah I say add. And now it's active. So if you try to create the credential, so if you try to add a new authenticator actually like this, okay? It will use that one instead of whatever you pick here, okay? That's kind of the idea.

You can see here, it creates the ID, the handle but everything is virtual, okay? So it's actually not being saved in your real Chrome. That's kind of the deal. So it's an emulator for web authentication credentials.

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