Changes:
- All exceptions in
webauthn.helpers.exceptions
now subclass the newwebauthn.helpers.exceptions.WebAuthnException
base 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'sPublicKeyCredentialCreationOptions
andPublicKeyCredentialRequestOptions
classes 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.InvalidClientDataJSONStructure
has been replaced bywebauthn.helpers.exceptions.InvalidJSONStructure
(#195)webauthn.helpers.json_loads_base64url_to_bytes()
has been removed (#195)- The
user_id
argument passed intogenerate_registration_options()
is nowOptional[bytes]
instead of a requiredstr
value. A random sequence of 64 bytes will be generated foruser_id
if 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
cbor2
in projects usingcbor2>=5.5.0
will no longer appear during registration and authentication response verification (#181)
Changes:
- The
credential
argument inverify_registration_response()
andverify_authentication_response()
can now also be a stringified JSONstr
or a plain JSONdict
version of a WebAuthn response (#172, #178) - Various methods will now raise
webauthn.helpers.exceptions.InvalidCBORData
when there is a problem parsing CBOR-encoded data (#179) - Updated dependencies to
cbor2==5.4.6
andcryptography==41.0.4
(#178)
Changes:
- Fix parsing error caused by registration responses from certain models of authenticators that incorrectly CBOR-encode their
authData
after 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.transports
property intoRegistrationCredential.response.transports
to better conform to upcoming WebAuthn JSON serialization method output (#150)
Changes:
- Update
cryptography
to 39.0.1 (and its dependencypyOpenSSL
to 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_attachment
value toRegistrationCredential
andAuthenticationCredential
, 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_type
andcredential_backed_up
values 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
bytes
fields, such asstr
values (#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
memoryviews
forBytesLike
properties 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
credential
docstring 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
bytes
to 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 π