MasterKale / SimpleWebAuthn

WebAuthn, Simplified. A collection of TypeScript-first libraries for simpler WebAuthn integration. Supports modern browsers, Node, Deno, and more.
https://simplewebauthn.dev
MIT License
1.63k stars 137 forks source link

Guides for passwordless support #304

Closed AkanshDivker closed 1 year ago

AkanshDivker commented 1 year ago

Apologies since this is not exactly an issue, but I was just looking to find out whether there is any estimate on when the additional guides or examples would be created, or if there are any other resources I could be pointed to. I've been trying to get the server portion of the library working to support passwordless but I've been having difficulty figuring it out. Not sure when the notice was added to the docs, so wanted to ask for a clarified update.

Thanks!

MasterKale commented 1 year ago

@AkanshDivker Yeah, it's true I've kinda slept on the whole cookbooks thing. Part of the reason is that a Microsoft colleague and I are trying to make https://passkeys.dev the definitive developers guide on how to implement passkeys, at least from a raw JS perspective (we don't want to be prescriptive about use of any front end dependencies like mine.)

That said, this issue you logged got the wheels turning in my head, and I think I might actually make SimpleWebAuthn more opinionated to encourage adoption of passkeys. That is, I'll change the defaults of some values in the four core @simplewebauthn/server methods to tune output for passkeys use cases, but not remove the ability to override the options so that sites using this lib for, say, second-factor-only can continue to do so.

In the mean time, if you can help me understand what difficulties you've had in trying to get SimpleWebAuthn to work when implementing passkeys, please share them here. Your observations will help me with this effort, including when I document all this on https://simplewebauthn.dev/docs/.

MasterKale commented 1 year ago

Oh yeah, there's currently a page for passkeys support here:

https://simplewebauthn.dev/docs/advanced/passkeys

Feedback on docs content is always welcome.

AkanshDivker commented 1 year ago

@MasterKale Thanks for your response! I apologize since it seems I completely missed the Passkeys section. At a quick glance, it seems to cover what I want to achieve, which is a completely passwordless solution. Passkey adoption seems to be the correct direction and I definitely feel more push toward that is needed. I'll give the passkey implementation a go and hopefully, I can get a proper understanding of it and get it working as intended.

I'm still relatively new to working with WebAuthn so some things might be a little over my head. There wasn't anything specifically wrong with the server guide, I understood its purpose for using it as 2FA. However, I was unable to grasp how I could properly modify it to support a passwordless only option. I also realized I was ignoring storing the current challenge and checking against it later.

I was a bit confused about generating registration options for a new user. My guess was that a check should be done to determine whether the user already has an account/credentials in the database, and if not, then pass the desired userID and userName into the object passed to generateRegistrationOptions?

Thank you :)

MasterKale commented 1 year ago

I was a bit confused about generating registration options for a new user. My guess was that a check should be done to determine whether the user already has an account/credentials in the database, and if not, then pass the desired userID and userName into the object passed to generateRegistrationOptions?

You shouldn't go full usernameless, the functionality isn't there yet in the spec to update a credential's username after creation if you allow for anonymous account creation, and then let them choose a username afterwards. That means it's highly recommended that you identify the user before you allow any authenticator to be registered.

How you do that is specific to your project, but that's my advice. Do an email confirmation link or something, then when they click the email to confirm their address use that to bootstrap a registration ceremony. At that point you can know a username (their email address), and generate a user ID for them, to use in registration options.

erickriva commented 1 year ago

However, I was unable to grasp how I could properly modify it to support a passwordless only option. I also realized I was ignoring storing the current challenge and checking against it later.

@MasterKale I had this exact same problem when started to learn how to use that. I still have some doubts: which is the best way to store the current challenge? Should it be in a specific DB? Memory-based DB?

MasterKale commented 1 year ago

I had this exact same problem when started to learn how to use that. I still have some doubts: which is the best way to store the current challenge? Should it be in a specific DB? Memory-based DB?

I like using Redis for this because you can setex() the challenge to expire in N minutes, or immediately upon receiving a response and attempt a validation (you only ever want to allow a challenge to be used once, even if the response fails verification.) A session ID in a cookie is an easy way to then pull up the challenge when you get back a response - when you store the challenge in Redis you can use the session ID as its key.

Redis might be considered overkill for this; storing the challenge in a typical DB is also an option. With an RDBMS you'd need to remember to delete the challenge after you get back the response that should have signed it. The technique I described above generally covers how challenges should be handled when working with this stuff.

AkanshDivker commented 1 year ago

You shouldn't go full usernameless, the functionality isn't there yet in the spec to update a credential's username after creation if you allow for anonymous account creation, and then let them choose a username afterwards. That means it's highly recommended that you identify the user before you allow any authenticator to be registered.

How you do that is specific to your project, but that's my advice. Do an email confirmation link or something, then when they click the email to confirm their address use that to bootstrap a registration ceremony. At that point you can know a username (their email address), and generate a user ID for them, to use in registration options.

Thanks for sharing, that sounds like a great idea! Happy to know about any best practices so that I can follow them. I wasn't planning on going usernameless, but I wasn't sure how or when would be the best place to formally assign a username and ID into the registration process. Your suggestion of bootstrapping after email confirmation seems to be the safest way that makes sense.

Thanks again!

MasterKale commented 1 year ago

I think this has turned into a good discussion-like topic, so I'm going to convert this over in case we want to continue this conversation.