NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #1448 most downloaded on PyPI
Pythonic WebAuthn
Last release 9 days ago
25 Sep 2026
Release timing varies
gaps range from 2 weeks to 4 months
Most releases are documented
notes for 40 of 45 stable releases
Nothing withdrawn
no release was ever pulled
9 years old
48 releases · first in 2018
verify_registration_response() now rejects responses with attestation statement formats that are not strings ( #288 , h/t @DarkaMaul )
Changes:
verify_registration_response() now rejects responses with attestation statement formats that are not strings (#288, h/t @DarkaMaul)verify_registration_response() and verify_authentication_response() now support use of PQC ML-DSA-44, ML-DSA-65, and ML-DSA-87 algorithms for credenti
Changes:
verify_registration_response() and verify_authentication_response() now support use of PQC ML-DSA-44, ML-DSA-65, and ML-DSA-87 algorithms for credential public key signature verification (#282)
generate_registration_options() will now encourage authenticators to create keypairs using EDDSA when available, signaling acceptance of ES256 or RS256 when EDDSA is unavailable (#284)One column per quarter.
"android-key" attestation verification is more tolerant of X.509 leaf certificates with values that violate ASN.1 DER parsing rules
Changes:
"android-key" attestation verification is more tolerant of X.509 leaf certificates with values that violate ASN.1 DER parsing rules (#277)cbor2>=5.6.5,<6.0.0 (#269, h/t @typestring; #272), and cryptography>=46.0.0 and pyOpenSSL>=26.0.0 (#278)"android-key" attestation has been added (#268)"tpm" attestation verification to prevent casing-related lookup issues (#275)webauthn.helpers.exceptions.InvalidRegistrationResponse when encountering bad data. Likewise, authentication verification will more consistently raise webauthn.helpers.exceptions.InvalidAuthenticationResponse when encountering bad data (#271, #273, #276, #280)verify_authentication_response() has been fixed (#266, h/t @Densaugeo)🚨🚨🚨 THIS RELEASE IS UNSUPPORTED. OFFICIAL PQC SUPPORT WILL ARRIVE IN A FUTURE RELEASE 🚨🚨🚨
Changes:
verify_registration_response() and verify_authentication_response() now support use of ML-DSA public keys for authenticators with PQC support. Run pip install dilithium-py to enable this capability (#260)This project now uses the pyasn1 library to parse ASN.1-encoded values ( #263 , h/t @ggirol-rc )
Changes:
dict type annotations have been replaced with Dict[str, Any] to satisfy stricter type checking setups (#262, h/t @typestring)The webauthn.helpers.options_to_json_dict helper has a new, optional bytes_encoder argument that accepts a Callable[[bytes], Any] method. This enables
Changes:
webauthn.helpers.options_to_json_dict helper has a new, optional bytes_encoder argument that accepts a Callable[[bytes], Any] method. This enables the use of custom encoding logic when serializing bytes values. When this argument is unspecified, bytes values will continue to be encoded into Base64URL (#257)The new webauthn.helpers.options_to_json_dict helper can be used to simplify registration and authentication options into a simple Dict[str, Any] valu
Changes:
webauthn.helpers.options_to_json_dict helper can be used to simplify registration and authentication options into a simple Dict[str, Any] value (#256)More X.509 validation exceptions will include the cause of the exception as reported by the third-party library handling the validation
Changes:
Update project to cryptography==44.0.2 and pyOpenSSL==25.0.0
Changes:
cryptography==44.0.2 and pyOpenSSL==25.0.0 (#250)Prevented "android-key" attestation tests from failing when it's after February 2nd
Changes:
"android-key" attestation tests from failing when it's after February 2nd (#244)A new require_user_presence argument has been added to verify_registration_response() to enable verification of WebAuthn responses generated through u
Changes:
require_user_presence argument has been added to verify_registration_response() to enable verification of WebAuthn responses generated through use of conditional create where the up bit in authData.flags will be False (#236, h/t @bschoenmaeckers)verify_authentication_response() has been updated to return user_verified as well to indicate whether or not the user performed user verification (#235, h/t @ggirol-rc)"android-key" attestation statements has been modernized in light of Android's latest observable behavior (#240)"android-safetynet" attestation statements now enforces the "basicIntegrity" flag instead of the "ctsProfileMatch" flag when determining device integrity (#241)An optional hints argument has been added to generate_registration_options() to specify one or more categories of authenticators for the browser to pr
Changes:
hints argument has been added to generate_registration_options() to specify one or more categories of authenticators for the browser to prioritize registration of. See webauthn.helpers.structs.PublicKeyCredentialHint for more information (#234)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
Changes:
cryptography==43.0.3 (#233, with thanks to @ds-cbo)All exceptions in webauthn.helpers.exceptions now subclass the new webauthn.helpers.exceptions.WebAuthnException base exception (#219, h/t @bschoenmae
New webauthn.helpers.parse_registration_options_json() and webauthn.helpers.parse_authentication_options_json() methods have been added to help replac
Changes:
webauthn.helpers.parse_registration_options_json() and webauthn.helpers.parse_authentication_options_json() methods have been added to help replace use of Pydantic's .parse_obj() on this library's PublicKeyCredentialCreationOptions and PublicKeyCredentialRequestOptions classes in projects upgrading to webauthn>=2.0.0. See Refactor Guidance below for more info (#210)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.
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 t
Changes:
Breaking Changes:
RegistrationCredential.parse_raw() can be replaced with calls to the new webauthn.helpers.parse_registration_credential_json()AuthenticationCredential.parse_raw() can be replaced with calls to the new webauthn.helpers.parse_authentication_credential_json()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 by webauthn.helpers.exceptions.InvalidJSONStructure (#195)webauthn.helpers.json_loads_base64url_to_bytes() has been removed (#195)user_id argument passed into generate_registration_options() is now Optional[bytes]
instead of a required str value. A random sequence of 64 bytes will be generated for user_id
if it is None (#197)
base64url_to_bytes() helperIf 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,
)
generate_registration_options() generate a user ID for youWhen 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
)
str argument to UTF-8 bytesThis 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'),
)
Deprecation warnings related to cbor2 in projects using cbor2>=5.5.0 will no longer appear during registration and authentication response verificatio…
Changes:
cbor2 in projects using cbor2>=5.5.0 will no longer appear during registration and authentication response verification (#181)The credential argument in verify_registration_response() and verify_authentication_response() can now also be a stringified JSON str or a plain JSON
Changes:
credential argument in verify_registration_response() and verify_authentication_response() can now also be a stringified JSON str or a plain JSON dict version of a WebAuthn response (#172, #178)webauthn.helpers.exceptions.InvalidCBORData when there is a problem parsing CBOR-encoded data (#179)cbor2==5.4.6 and cryptography==41.0.4 (#178)Fix parsing error caused by registration responses from certain models of authenticators that incorrectly CBOR-encode their authData after creating an
Changes:
authData after creating an Ed25519 public keys (#167)Support use in projects using either Pydantic v1 or v2
Changes:
Keep using Pydantic v1.x for now
Update dependency versions in setup.py
Changes:
.. _v1-8:
Move the RegistrationCredential.transports property into RegistrationCredential.response.transports to better conform to upcoming WebAuthn JSON serial
Changes:
RegistrationCredential.transports property into RegistrationCredential.response.transports to better conform to upcoming WebAuthn JSON serialization method output (#150)Update cryptography to 39.0.1 (and its dependency pyOpenSSL to 23.0.0)
Changes:
cryptography to 39.0.1 (and its dependency pyOpenSSL to 23.0.0) (#148)
.. _v1-7-1:
Add support for from webauthn import * syntax with proper use of __all__
Changes:
from webauthn import * syntax with proper use of __all__ (#146)int_from_bytes where it failed to accept
bytearray... _v1-7:
Add new authenticator_attachment value to RegistrationCredential and AuthenticationCredential, defining the attachment of the authenticator that compl
Changes:
authenticator_attachment value to RegistrationCredential and AuthenticationCredential, defining the attachment of the authenticator that completed a corresponding ceremony, as it may be returned by the WebAuthn API (#141)Add new credential_device_type and credential_backed_up values to output from verify_registration_response() and verify_authentication_response()
Restore the ability to pass more common bytes-like values for bytes fields, such as str values
Changes:
bytes fields, such as str values (#132).. _v1-5-1:
Refine support for bytes-like inputs to comply with stricter mypy configurations
Changes:
UserWarning when used with cffi 1.8.3.cryptography from compiling against
OpenSSL 1.0.2i... _v1-5:
Fix authenticator data parsing to correctly parse extension data when present
Add support for memoryviews for BytesLike properties including credential_public_key, authenticator_data, etc...
Changes:
memoryviews for BytesLike properties including credential_public_key, authenticator_data, etc...Switch back from attrs + cattrs to Pydantic while preserving support for bytes-like values in subclasses of WebAuthnBaseModel.
Changes:
bytes-like values in subclasses of WebAuthnBaseModel.
Clarify credential docstring for verify_authentication_response()
Changes:
credential docstring for verify_authentication_response()EVP_PKEY object that caused errors with
pyOpenSSL... _v1-2:
Switched from Pydantic to the combination of attrs + cattrs. This achieves more-Pythonic library behavior when used in a project alongside other third
Changes:
bytes to represent such values as credential IDs and public keys.Fixed SafetyNet attestation statement verification failing due to server time drift
Changes:
Fixed SafetyNet unit test failing due to expired x5c certs (see PR #99)
Changes:
We now ship OS X wheels that statically link OpenSSL by default. When installing a wheel on OS X 10.10+ (and using a Python compiled against the 10.10 SDK) users will no longer need to compile. See /installation for alternate installation methods if required.
Set the default string mask to UTF-8 in the OpenSSL backend to resolve character encoding issues with older versions of OpenSSL.
Several new OpenSSL bindings have been added to support a future pyOpenSSL release.
Raise an error during install on PyPy < 2.6. 1.0+ requires PyPy 2.6+.
This preview release of the revitalized py_webauthn library features an entirely new API, as well as support for all attestation statement formats inc
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:
Practical examples are included in the examples/ directory to serve as a primary reference for now on how to use the new library functionality.
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:
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:
Nothing published for this version
Preview release of the revitalized py_webauthn library. See PR #95
Preview release of the revitalized py_webauthn library. See PR #95
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Deprecated salt_length on ~cryptography.hazmat.primitives.asymmetric.padding.MGF1 and added it to ~cryptography.hazmat.primitives.asymmetric.padding.P…
Deprecated salt_length on ~cryptography.hazmat.primitives.asymmetric.padding.MGF1 and added it to ~cryptography.hazmat.primitives.asymmetric.padding.PSS. It will be removed from MGF1 in two releases per our /api-stability policy.
Added SEED support.
Added ~cryptography.hazmat.primitives.cmac.CMAC.
Added decryption support to ~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey and encryption support to ~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.
Added signature support to ~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey and verification support to ~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey.
Nothing published for this version
Added ~cryptography.hazmat.primitives.twofactor.hotp.HOTP.
Added ~cryptography.hazmat.primitives.twofactor.hotp.HOTP.
Added ~cryptography.hazmat.primitives.twofactor.totp.TOTP.
Added IDEA support.
Added signature support to ~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey and verification support to ~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.
Moved test vectors to the new cryptography_vectors package.
Removed register_cipher_adapter method from CipherBackend.
Added commoncrypto.
Added initial commoncrypto.
Removed register_cipher_adapter method from CipherBackend.
Added support for the OpenSSL backend under Windows.
Improved thread-safety for the OpenSSL backend.
Fixed compilation on systems where OpenSSL's ec.h header is not available, such as CentOS.
Added ~cryptography.hazmat.primitives.kdf.pbkdf2.PBKDF2HMAC.
Added ~cryptography.hazmat.primitives.kdf.hkdf.HKDF.
Added multibackend.
Set default random for openssl to the OS random engine.
Added CAST5 (CAST-128) support.
.. _as documented here: https://docs.rs/openssl/latest/openssl/#automatic .. _main: https://github.com/pyca/cryptography/ .. _cffi: https://cffi.readt
.. _as documented here: https://docs.rs/openssl/latest/openssl/#automatic
.. _main: https://github.com/pyca/cryptography/
.. _cffi: https://cffi.readthedocs.io/
.. _aws-lc: https://github.com/aws/aws-lc
.. _Dropped support for win_arm64 wheels: https://github.com/pyca/cryptography/pull/14216
Your coding agent can read these notes before it upgrades. Set up the MCP server →