Changes:
- This project now uses the pyasn1 library to parse ASN.1-encoded values (#263, h/t @ggirol-rc)
- Some bare
dicttype annotations have been replaced withDict[str, Any]to satisfy stricter type checking setups (#262, h/t @typestring)
Changes:
- The
webauthn.helpers.options_to_json_dicthelper has a new, optionalbytes_encoderargument that accepts aCallable[[bytes], Any]method. This enables the use of custom encoding logic when serializingbytesvalues. When this argument is unspecified,bytesvalues will continue to be encoded into Base64URL (#257)
Changes:
- The new
webauthn.helpers.options_to_json_dicthelper can be used to simplify registration and authentication options into a simpleDict[str, Any]value (#256)
Changes:
- More X.509 validation exceptions will include the cause of the exception as reported by the third-party library handling the validation (#255)
Changes:
- Update project to
cryptography==44.0.2andpyOpenSSL==25.0.0(#250)
Changes:
- Prevented
"android-key"attestation tests from failing when it's after February 2nd (#244)
Changes:
- A new
require_user_presenceargument has been added toverify_registration_response()to enable verification of WebAuthn responses generated through use of conditional create where theupbit inauthData.flagswill beFalse(#236, h/t @bschoenmaeckers) verify_authentication_response()has been updated to returnuser_verifiedas well to indicate whether or not the user performed user verification (#235, h/t @ggirol-rc)- Verification of
"android-key"attestation statements has been modernized in light of Android's latest observable behavior (#240) - Verification of
"android-safetynet"attestation statements now enforces the"basicIntegrity"flag instead of the"ctsProfileMatch"flag when determining device integrity (#241) - The list of known TPM manufacturers has been updated (#242)
Changes:
- An optional
hintsargument has been added togenerate_registration_options()to specify one or more categories of authenticators for the browser to prioritize registration of. Seewebauthn.helpers.structs.PublicKeyCredentialHintfor more information (#234)
Changes:
- The minimum supported version of Python has been bumped up to Python 3.9, with ongoing testing from Python 3.9 through Python 3.13. Dependencies have been updated as well, including upgrading to
cryptography==43.0.3(#233, with thanks to @ds-cbo)
Changes:
- All exceptions in
webauthn.helpers.exceptionsnow subclass the newwebauthn.helpers.exceptions.WebAuthnExceptionbase exception (#219, h/t @bschoenmaeckers) - Support has been added for the new
"smart-card"transport (#221)
Changes:
- New
webauthn.helpers.parse_registration_options_json()andwebauthn.helpers.parse_authentication_options_json()methods have been added to help replace use of Pydantic's.parse_obj()on this library'sPublicKeyCredentialCreationOptionsandPublicKeyCredentialRequestOptionsclasses in projects upgrading towebauthn>=2.0.0. See Refactor Guidance below for more info (#210) - Updated dependencies to
cryptography==42.0.5(#212)
Taking an example from registration: imagine a py_webauthn v1.11.1 scenario in which a project using this library wanted to retrieve output from generate_registration_options(), serialized to JSON using webauthn.helpers.options_to_json() and then stored in a cache or DB, and turn it back into an instance of PublicKeyCredentialCreationOptions:
# webauthn==1.11.1
json_reg_options: dict = get_stored_registration_options(session_id)
parsed_reg_options = PublicKeyCredentialCreationOptions.parse_obj(
json_reg_options,
)py_webauthn v2.0.0+ removed use of Pydantic so .parse_obj() is no longer available on PublicKeyCredentialCreationOptions. It will become possible to refactor away this use of .parse_obj() with the new webauthn.helpers.parse_registration_options_json() in this release:
# webauthn==2.1.0
from webauthn.helpers import parse_registration_options_json
json_reg_options: dict = get_stored_registration_options(session_id)
parsed_reg_options: PublicKeyCredentialCreationOptions = parse_registration_options_json(
json_reg_options,
)This same logic applies to calls to PublicKeyCredentialRequestOptions.parse_obj() - these calls can be replaced with the new webauthn.helpers.parse_authentication_options_json() in this release as well.
Changes:
- See Breaking Changes below
Breaking Changes:
- Pydantic is no longer used by py_webauthn. If your project calls any Pydantic-specific methods on classes provided by py_webauthn then you will need to refactor those calls accordingly. Typical use of py_webauthn should not need any major refactor related to this change, but please see Breaking Changes below (#195)
webauthn.helpers.generate_challenge()now always generates 64 random bytes and no longer accepts any arguments. Refactor your existing calls to remove any arguments (#198)webauthn.helpers.exceptions.InvalidClientDataJSONStructurehas been replaced bywebauthn.helpers.exceptions.InvalidJSONStructure(#195)webauthn.helpers.json_loads_base64url_to_bytes()has been removed (#195)- The
user_idargument passed intogenerate_registration_options()is nowOptional[bytes]instead of a requiredstrvalue. A random sequence of 64 bytes will be generated foruser_idif it isNone(#197)- There are a few options available to refactor existing calls:
If you already store your WebAuthn user ID bytes as base64url-encoded strings then you can simply decode these strings to bytes using an included helper:
Before:
options = generate_registration_options(
# ...
user_id: "3ZPk1HGhX_cul7z5UydfZE_vgnUYkOVshDNcvI1ILyQ",
)After:
from webauthn.helpers import bytes_to_base64url
options = generate_registration_options(
# ...
user_id: bytes_to_base64url("3ZPk1HGhX_cul7z5UydfZE_vgnUYkOVshDNcvI1ILyQ"),
)WebAuthn strongly encourages Relying Parties to use 64 randomized bytes for every user ID you pass into navigator.credentials.create(). This would be a second identifier used exclusively for WebAuthn that you associate along with your typical internal user ID.
py_webauthn includes a generate_user_handle() helper that can simplify the task of creating this special user identifier for your existing users in one go:
from webauthn.helpers import generate_user_handle
# Pseudocode (imagine this is in some kind of migration script)
for user in get_all_users_in_db():
add_webauthn_user_id_to_db_for_user(
current_user=user.id,
webauthn_user_id=generate_user_handle(), # Generates 64 random bytes
)You can also use this method when creating new users to ensure that all subsequent users have a WebAuthn-specific identifier as well:
from webauthn.helpers import generate_user_handle
# ...existing user onboarding logic...
# Pseudocode
create_new_user_in_db(
# ...
webauthn_user_id=generate_user_handle(),
)Once your users are assigned their second WebAuthn-specific ID you can then pass those bytes into generate_registration_options() on subsequent calls:
# Pseudocode
webauthn_user_id: bytes = get_webauthn_user_id_bytes_from_db(current_user.id)
options = generate_registration_options(
# ...
user_id=webauthn_user_id,
)When the user_id argument is omitted then a random 64-byte identifier will be generated for you:
Before:
options = generate_registration_options(
# ...
user_id: "USERIDGOESHERE",
)After:
# Pseudocode
webauthn_user_id: bytes | None = get_webauthn_user_id_bytes_from_db(
current_user=current_user.id,
)
options = generate_registration_options(
# ...
user_id=webauthn_user_id,
)
if webauthn_user_id is None:
# Pseudocode
store_webauthn_user_id_bytes_in_your_db(
current_user=current_user.id,
webauthn_user_id=options.user.id, # Randomly generated 64-bytes
)This technique is a quick win, but can be prone to base64url-related encoding and decoding quirks between browsers. It is recommended you quickly follow this up with Option 2 or Option 3 above:
Before:
options = generate_registration_options(
# ...
user_id: "USERIDGOESHERE",
)After:
options = generate_registration_options(
# ...
user_id: "USERIDGOESHERE".encode('utf-8'),
)Changes:
- Deprecation warnings related to
cbor2in projects usingcbor2>=5.5.0will no longer appear during registration and authentication response verification (#181)
Changes:
- The
credentialargument inverify_registration_response()andverify_authentication_response()can now also be a stringified JSONstror a plain JSONdictversion of a WebAuthn response (#172, #178) - Various methods will now raise
webauthn.helpers.exceptions.InvalidCBORDatawhen there is a problem parsing CBOR-encoded data (#179) - Updated dependencies to
cbor2==5.4.6andcryptography==41.0.4(#178)
Changes:
- Fix parsing error caused by registration responses from certain models of authenticators that incorrectly CBOR-encode their
authDataafter creating an Ed25519 public keys (#167)
Changes:
- Support use in projects using either Pydantic v1 or v2 (#166)
Changes:
Changes:
- Update dependency versions in setup.py (#151)
Changes:
- Move the
RegistrationCredential.transportsproperty intoRegistrationCredential.response.transportsto better conform to upcoming WebAuthn JSON serialization method output (#150)
Changes:
- Update
cryptographyto 39.0.1 (and its dependencypyOpenSSLto 23.0.0) (#148)- See "39.0.1 - 2023-02-07" in cryptography's CHANGELOG for more info
Changes:
- Add support for
from webauthn import *syntax with proper use of__all__(#146)
Changes:
- Add new
authenticator_attachmentvalue toRegistrationCredentialandAuthenticationCredential, defining the attachment of the authenticator that completed a corresponding ceremony, as it may be returned by the WebAuthn API (#141)
Changes:
- Add new
credential_device_typeandcredential_backed_upvalues to output fromverify_registration_response()andverify_authentication_response()(#136) - Add support for the new
"hybrid"transport (the generalized, eventual successor to"cable") (#137)
Changes:
- Restore the ability to pass more common bytes-like values for
bytesfields, such asstrvalues (#132)
Changes:
- Refine support for bytes-like inputs to comply with stricter mypy configurations (#130)
Changes:
- Fix authenticator data parsing to correctly parse extension data when present (#125)
- Add support for the new
"cable"transport (#129)
Changes:
- Add support for
memoryviewsforBytesLikeproperties includingcredential_public_key,authenticator_data, etc...
Changes:
- Switch back from attrs + cattrs to Pydantic while preserving support for
bytes-like values in subclasses ofWebAuthnBaseModel.- See issue #113 for more context
Changes:
- Clarify
credentialdocstring forverify_authentication_response()
Changes:
- Switched from Pydantic to the combination of attrs + cattrs. This achieves more-Pythonic library behavior when used in a project alongside other third-party packages that use subclasses of
bytesto represent such values as credential IDs and public keys.
Changes:
- Fixed SafetyNet attestation statement verification failing due to server time drift
- Added py.typed file to indicate type information is present (PEP-561)
Changes:
- Fixed SafetyNet unit test failing due to expired x5c certs (see PR #99)
This preview release of the revitalized py_webauthn library features an entirely new API, as well as support for all attestation statement formats included in L2 of the WebAuthn spec:
- Packed
- TPM
- Android Key
- Android SafetyNet
- FIDO U2F
- Apple
- None
Practical examples are included in the examples/ directory to serve as a primary reference for now on how to use the new library functionality.
Changes:
- Everything. The entire package was replaced with a new library with a new API. Check it out π