Search code examples
javascriptauthenticationsafariwebauthnfido

FIDO2 / WebAuthn Heuristic discovery of ambient /pre-authorized user(s) at authentication time


Edit respose to @cody salas

Following on from your sensible and detailed break down: -

Require Username:

Yes this seems well understood. The RP prompts for username/other-id and finds all credentials that are offered up in an array to the authenticator. Peachy!

Usernameless:

I need the "nuance" you refer to please. What (if any) filter(s) is applied to the returned credentials?

  1. Global scope === Windows Hello User
  2. Google login(s)
  3. Other App logins

My Windows Hello Identity does NOT work with my Yubikey so I can't test :-(

Shared Accounts:

Ok, forget about the Beatles analogy, let's imagine one user (Our ex-PM :-) with multiple identities. ScoMo-Treasury, ScoMo-Health, ScoMo-Resources etc. What does a wildcard GET return?

End Edit 1

UA Credential Safe interogation.

Scenario:

  1. Tri-Bank has 1 or more registered users from this device (My Windows Hello PC "Bad Boy").
  2. There is no active session or ambient user to the RP (sub)domain. (Seeing local/session storage deprecated but all cookies also expired)
  3. I simply cannot see a usernameless login interaction possibility
  4. I will investigate that UPVA is deterministic on multi-user device but the spec is not only non-canonical, it seems to be off in fairy land :-(

WRT: -

Authentication WebAuthn-3 and Authentication WebAuthn-2

Please expand on point .2

The script asks the client for an Authentication Assertion, providing as much information as possible to narrow the choice of acceptable credentials for the user. This can be obtained from the data that was stored locally after registration, or by other means such as prompting the user for a username.

Which spec can we refer to (CTAP-10?) that will enlighten us to what is returned to a GET call with an empty "allowCredentials"?

How can the RP refine the user selection granularirty without a .GET that either identifies a single user or returns new Error("non-deterministic");

Does no one else see this as pivitol?

If we always have to ask for username please just say "We always have to identify username first!"

Otherwise could the user be prompted for we have Ringo, and Paul registered; which one do you want :-(

And yes, I know Paul can't login to Ringo's account without his thumb. I'm alluding to the unacceptable disclosure of Ringo's financial activity to Paul. Probably not a big deal unless it was John :-)

Please explain the FIDO2 versus OAUTH2.0 philisophical diversions pros/cons here!

OAUTH2.0 :- Would you like to continue as [email protected]? Done! no password, biometric, PIN, blah, blah, blah, pre-authenticated and trusted FIDO2 :- I've got a UPVA that I'll probably have to test you on or a number Authentication methods for a number of users that I'll get you to pick from

Sounds about right???


Solution

  • Let's break this problem down into three different sections: Requiring a username, usernameless logins, and shared accounts

    Requiring a username

    Using an identifier is the only way to narrow down which authenticators are acceptable for an auth session. Note the use of identifier. The spec calls out username as it's extremely common, and familiar to users, but another mechanism can be used as an identifier if your environment/requirements allows for it.

    Also keep in mind that this flow works well for users who are using an authenticator or ecosystem that does NOT support discoverable credentials.

    I have some development guidance here if you wish to see some expanded code samples.

    This won't entirely solve your problem if you are using a shared Windows Hello account. All John has to do is type the identifier "Paul", type in the PIN/Fingerprint, and have access. Overall you don't want to share authenticators, but I'll touch on that later in this comment.

    Usernameless login

    Remember this login flow will only work for users in an ecosystem that supports discoverable credentials. You've mentioned Windows Hello so you are in good hands. In this flow a relying party sends an empty allowCredentials list because it has no idea who is triggering the auth session. The relying party is essentially saying "send over a credential, and I'll attempt to validate it". There's more nuance to this statement, especially depending on the identity provider you are using, but that's the overall gist.

    Usernameless can be broken down further depending on if you're using a security key, or platform authenticator. But during the GET() ceremony all credentials tied to your current origin will be shown depending on the authenticator that you activate. So if you fingerprint into Windows Hello, all the credentials for the current origin tied into the single Windows Hello account will be shown. If you activate your security key, all the credentials on the device for the current origin will be shown that exist on the device.

    Shared accounts/workstations

    So we'll continue with your Beatles example above. They can all share one computer, but this is where you need to question if they should be sharing the same Windows Hello account. If you register a credential using the Windows Hello authenticator, then anyone with the PIN/Fingerprint to that account will be able to leverage credentials on the account + device combo.

    At the end of the day this will depend on how many accounts are tied to your workstation.

    If you are adamant about the Beatles all sharing one Windows Hello account, on one workstation, then maybe they need separate personal authenticators, like a security key. That way no matter who is using the shared account, they still have independent credentials (unless Ringo decides to register Windows Hello, rather than his security key)

    Otherwise, if each Beatle has their own Windows Hello account, they could log out/login in whenever one of the lads needs to check their bank account. In this case they will only be shown the credentials tied to their specific Windows Hello account

    Hope this helps


    Update 8/22

    Glad my responses are helping so far - see below for answers to your additional follow-ups

    Usernameless nuance

    When I say nuance, I’m mostly referring to the not “one size fits all” of identity/auth providers. I can give you the code to my project using Cognito, but if you’re using Azure AD then there might be differences in the parameters that you pass to your RP. MOST of the code and logic will look the same, but it’s the small differences that might require more/less data.

    For instance, let’s say that both Identity providers A and B support WebAuthn, and both will support discoverable credentials/usernamless login. But imagine that A requires that you call to its API noting the user's identifier, and B can derive the identifier from the get() response. They both accomplish the same task, but require slight modifications to the implementation

    Shared accounts

    I ran a test on my Windows machine (Windows 10, Windows Hello consumer). I created a Discoverable credential on account A using Windows Hello. I signed out, and logged in as account B using Windows Hello. I attempted to login to the same website, but I was unable to use the credential created by account A as account B.

    So if your PM creates a credential as ScoMo-Trasury, they won’t be able to use the same credential as ScoMo-Health.

    The wildcard get() method will only return the credentials for the account currently logged into Windows.