Giter Club home page Giter Club logo

Comments (16)

MasterKale avatar MasterKale commented on May 23, 2024 1

The main use of the user handle is to identify the user account in such authentication ceremonies, but the credential ID could be used instead. The main differences are that the credential ID is chosen by the authenticator and is unique for each credential, while the user handle is chosen by the Relying Party and ought to be the same for all credentials registered to the same user account.

There's also a subtle nuance in here that credential IDs are chosen by the authenticator, but user IDs are chosen by the RP. That makes user IDs "better" from the RP's perspective because it's a value that the RP controls and can predict the shape of vs the variability observable in credential ID lengths.

For the secondary use case, it reads like the spec suggests to use the same user id for all authenticators that belong to the same user. This would imply that using random user ids is not ideal?

One of the main goals of using random identifiers for user.id is to preserve user privacy by not using email addresses or usernames that could be used to link a user across multiple sites, even sites that don't use passkeys at all! I missed that the spec says "ought to be the same for all credentials registered to the same user account", but honestly if you're going this route (vs specifying user IDs yourself) you could just as easily use a lookup table to handle random user IDs for every credential that all link back internally to a single DB user ID 🤔

from simplewebauthn.

MasterKale avatar MasterKale commented on May 23, 2024 1

(That said I still personally think it's okay to simply look up users by credential ID; I haven't heard of anyone running into issues with this approach. It's stuff like this that makes it hard to suggest the "best" way to do anything with SimpleWebAuthn: RP use cases and risk models are so varied I try to find a middle ground that'll not make a ton of work for any one type of RP...)

from simplewebauthn.

P4sca1 avatar P4sca1 commented on May 23, 2024 1

Thank you for the detailed answer and your continued work on the SimpleWebAuthn library!
I decided to continue using the user ids from database (incremental primary keys) as the user handle. They are not random and allow to identify a user within my application (at least find the associated username), but I do not consider this to be a privacy issue for my application. There is no email or real names revealed.
For authentication I continue looking up passkeys in my database based on the base64 credential id, instead of the user handle. This seems to be fine by the spec and is working fine. The user handle is not guaranteed to exist or exists in a different format for authenticators, that have been generated using previous registration options. The credential id is always there.

from simplewebauthn.

MasterKale avatar MasterKale commented on May 23, 2024 1

The user handle is not guaranteed to exist or exists in a different format for authenticators, that have been generated using previous registration options. The credential id is always there.

This is another reason I started looking up users by credential ID and never really looked back. Nowadays userHandle is almost always being returned, but not even L3 is going to make userHandle required so as of 2024 RPs will still have to prepare to handle its absence. And when userHandle is unavailable, how else can you look up the user? By credential ID...such is the way this stuff goes 😂

from simplewebauthn.

spendres avatar spendres commented on May 23, 2024

I am using them now for the userID. I suspect that they would fit within your proposed 64 byte Uint8Array type, but have not tested to determine if this would break my code.

Please consider using ULIDs for your userID generation given their benefits in data storage: more info

from simplewebauthn.

MasterKale avatar MasterKale commented on May 23, 2024

I still think by default it's a good idea for me to generate completely random values when userID is omitted. However in your case there's nothing about what I'm proposing that would prevent you from using ULIDs for userID, so long as you figured out a way to convert them to a Uint8Array that you're comfortable with.

from simplewebauthn.

rimu avatar rimu commented on May 23, 2024

so long as you figured out a way to convert them to a Uint8Array that you're comfortable with.

I have not...

I'm having some trouble with this - I let py_webauthn generate a user id from the backend (it gets encoded to "OPclcKTH6cjyjoRncpBrvKaepPz4eagbzFtOVnYCmANpUx0Vntm1lzlabOri5BF97CLNfTL440SIhbqwd459eQ") and then I'm converting that to a Uint8Array:

// Convert base64url encoded bytes into a Uint8Array. Used by passkeys.
const decodeBase64 = (encoded) => {
    return new Uint8Array(atob(encoded)
        .split('')
        .map((c) => c.charCodeAt(0)));
};

const decodeBase64Url = (input) => {
    try {
        return decodeBase64(input.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, ''));
    }
    catch (_a) {
        throw new TypeError('The input to be decoded is not correctly encoded.');
    }
};

I get 64 elements:

64.

But then startRegistration() has an exception "TypeError: User ID was not between 1 and 64 characters".

Any tips?

from simplewebauthn.

MasterKale avatar MasterKale commented on May 23, 2024

I'm having some trouble with this - I let py_webauthn generate a user id from the backend (it gets encoded to "OPclcKTH6cjyjoRncpBrvKaepPz4eagbzFtOVnYCmANpUx0Vntm1lzlabOri5BF97CLNfTL440SIhbqwd459eQ") and then I'm converting that to a Uint8Array

@rimu Are you feeding output from generate_registration_options() in py_webauthn to startRegistration() in @simplewebauthn/browser? If so you're intended to pass in the JSON options as-is and let startRegistration() take care of converting a value like OPclcKTH6cjyjoRncpBrvKaepPz4eagbzFtOVnYCmANpUx0Vntm1lzlabOri5BF97CLNfTL440SIhbqwd459eQ into the bytes that navigator.credentials.create() expects.

from simplewebauthn.

rimu avatar rimu commented on May 23, 2024

Ah, yes, now I can see where startRegistration does the conversion. I still get the same error, though.

I'm using 9.0.1 which is a bit old. That is the version that <script src="https://unpkg.com/@simplewebauthn/browser/dist/bundle/index.umd.min.js"></script> provides. Would it help if I was using 9.0.3?

from simplewebauthn.

rimu avatar rimu commented on May 23, 2024

Solved by using a shorter user_id: duo-labs/py_webauthn#199 (comment)

from simplewebauthn.

MasterKale avatar MasterKale commented on May 23, 2024

These changes are now available in the recently-published @simplewebauthn/[email protected], @simplewebauthn/[email protected], and @simplewebauthn/[email protected] ✌️

from simplewebauthn.

P4sca1 avatar P4sca1 commented on May 23, 2024

@MasterKale Is it required to save the random generated user ID value in the database? From my understanding, it is randomly generated in generateRegistrationOptions but then it is never validated in the future. Do I miss something?
I previously used internal user ids (ascending integer ids) for the userId field, but I think I can just ignore the field entirely with v10? What is the value even for? Does it need to be known in the backend?

from simplewebauthn.

wparad avatar wparad commented on May 23, 2024

@MasterKale Is it required to save the random generated user ID value in the database? From my understanding, it is randomly generated in generateRegistrationOptions but then it is never validated in the future. Do I miss something? I previously used internal user ids (ascending integer ids) for the userId field, but I think I can just ignore the field entirely with v10? What is the value even for? Does it need to be known in the backend?

@P4sca1, The userId is the userId, if you aren't using the userId how are you identifying who the user is?

from simplewebauthn.

P4sca1 avatar P4sca1 commented on May 23, 2024

I create a HTTP session when the authentication / registration process starts which contains the user id and WebAuthn challenge.
When verifying passkey authentication request, I select the Passkey with the given base64CredentialId. The resulting Passkey object contains the userId.

from simplewebauthn.

P4sca1 avatar P4sca1 commented on May 23, 2024

Okay, I found it in the spec (emphasis mine):

A user handle is an identifier for a user account, specified by the Relying Party as user.id during registration. Discoverable credentials store this identifier and MUST return it as response.userHandle in authentication ceremonies started with an empty allowCredentials argument.

The main use of the user handle is to identify the user account in such authentication ceremonies, but the credential ID could be used instead. The main differences are that the credential ID is chosen by the authenticator and is unique for each credential, while the user handle is chosen by the Relying Party and ought to be the same for all credentials registered to the same user account.

Authenticators map pairs of RP ID and user handle to public key credential sources. As a consequence, an authenticator will store at most one discoverable credential per user handle per Relying Party. Therefore a secondary use of the user handle is to allow authenticators to know when to replace an existing discoverable credential with a new one during the registration ceremony.

https://www.w3.org/TR/webauthn-3/#user-handle

For the secondary use case, it reads like the spec suggests to use the same user id for all authenticators that belong to the same user. This would imply that using random user ids is not ideal?

from simplewebauthn.

P4sca1 avatar P4sca1 commented on May 23, 2024

From https://www.w3.org/TR/webauthn-3/#sctn-user-handle-privacy:

It is RECOMMENDED to let the user handle be 64 random bytes, and store this value in the user account.

from simplewebauthn.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.