Skip to content

Commit

Permalink
Merge pull request #172 from jpaniagualaconich/avoid-pydantic-symbols
Browse files Browse the repository at this point in the history
avoid reliance on pydantic symbols
  • Loading branch information
MasterKale committed Sep 29, 2023
2 parents 56acd35 + 0159974 commit 6ac0f9d
Show file tree
Hide file tree
Showing 20 changed files with 244 additions and 155 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Changelog
## Unreleased

**Changes:**

- Avoid reliance on pydantic symbols in the public interface ([#172](https://github.com/duo-labs/py_webauthn/pull/172))
- Allow `verify_registration_response` and `verify_authentication_response` to receive credentials in JSON format

## v1.10.1

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Generally, the library makes the following assumptions about how a Relying Party

The examples mentioned below include uses of the `options_to_json()` helper (see above) to show how easily `bytes` values in registration and authentication options can be encoded to base64url for transmission to the front end.

The examples also include demonstrations of how to pass JSON-ified responses, using base64url encoding for `ArrayBuffer` values, into `RegistrationCredential.parse_raw()` and `AuthenticationCredential.parse_raw()` to be automatically parsed by the methods in this library. An RP can pair this with corresponding custom front end logic, or one of several frontend-specific libraries (like [@simplewebauthn/browser](https://www.npmjs.com/package/@simplewebauthn/browser), for example) to handle encoding and decoding such values to and from JSON.
The examples also include demonstrations of how to pass JSON-ified responses, using base64url encoding for `ArrayBuffer` values, into `parse_registration_credential_json` and `parse_authentication_credential_json` to be automatically parsed by the methods in this library. An RP can pair this with corresponding custom front end logic, or one of several frontend-specific libraries (like [@simplewebauthn/browser](https://www.npmjs.com/package/@simplewebauthn/browser), for example) to handle encoding and decoding such values to and from JSON.

Other arguments into this library's methods that are defined as `bytes` are intended to be values stored entirely on the server. Such values can more easily exist as `bytes` without needing potentially extraneous encoding and decoding into other formats. Any encoding or decoding of such values in the name of storing them between steps in a WebAuthn ceremony is left up to the RP to achieve in an implementation-specific manner.

Expand Down
13 changes: 7 additions & 6 deletions examples/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
base64url_to_bytes,
)
from webauthn.helpers.structs import (
PYDANTIC_V2,
PublicKeyCredentialDescriptor,
UserVerificationRequirement,
AuthenticationCredential,
)

################
Expand Down Expand Up @@ -40,8 +40,7 @@

# Authentication Response Verification
authentication_verification = verify_authentication_response(
credential=AuthenticationCredential.parse_raw(
"""{
credential="""{
"id": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"rawId": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"response": {
Expand All @@ -53,8 +52,7 @@
"type": "public-key",
"authenticatorAttachment": "cross-platform",
"clientExtensionResults": {}
}"""
),
}""",
expected_challenge=base64url_to_bytes(
"iPmAi1Pp1XL6oAgq3PWZtZPnZa1zFUDoGbaQ0_KvVG1lF2s3Rt_3o4uSzccy0tmcTIpTTT4BU1T-I4maavndjQ"
),
Expand All @@ -67,5 +65,8 @@
require_user_verification=True,
)
print("\n[Authentication Verification]")
print(authentication_verification.json(indent=2))
if PYDANTIC_V2:
print(authentication_verification.model_dump_json(indent=2))
else:
print(authentication_verification.json(indent=2))
assert authentication_verification.new_sign_count == 1
13 changes: 7 additions & 6 deletions examples/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
)
from webauthn.helpers.cose import COSEAlgorithmIdentifier
from webauthn.helpers.structs import (
PYDANTIC_V2,
AttestationConveyancePreference,
AuthenticatorAttachment,
AuthenticatorSelectionCriteria,
PublicKeyCredentialDescriptor,
ResidentKeyRequirement,
RegistrationCredential,
)

################
Expand Down Expand Up @@ -56,8 +56,7 @@

# Registration Response Verification
registration_verification = verify_registration_response(
credential=RegistrationCredential.parse_raw(
"""{
credential="""{
"id": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"rawId": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"response": {
Expand All @@ -68,8 +67,7 @@
"type": "public-key",
"clientExtensionResults": {},
"authenticatorAttachment": "platform"
}"""
),
}""",
expected_challenge=base64url_to_bytes(
"CeTWogmg0cchuiYuFrv8DXXdMZSIQRVZJOga_xayVVEcBj0Cw3y73yhD4FkGSe-RrP6hPJJAIm3LVien4hXELg"
),
Expand All @@ -79,7 +77,10 @@
)

print("\n[Registration Verification - None]")
print(registration_verification.json(indent=2))
if PYDANTIC_V2:
print(registration_verification.model_dump_json(indent=2))
else:
print(registration_verification.json(indent=2))
assert registration_verification.credential_id == base64url_to_bytes(
"ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s"
)
6 changes: 3 additions & 3 deletions tests/test_structs.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
from unittest import TestCase

from webauthn.helpers import parse_registration_credential_json
from webauthn.helpers.structs import (
RegistrationCredential,
AuthenticatorTransport,
AuthenticatorAttachment,
)


class TestStructsRegistrationCredential(TestCase):
def test_registration_credential_parse_raw(self):
def test_parse_registration_credential_json(self):
"""
Check that we can properly parse some values that aren't really here-or-there for response
verification, but can still be useful to RP's to fine-tune the WebAuthn experience.
"""
parsed = RegistrationCredential.parse_raw(
parsed = parse_registration_credential_json(
"""{
"id": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"rawId": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
Expand Down
104 changes: 63 additions & 41 deletions tests/test_verify_authentication_response.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
from unittest import TestCase

from webauthn import verify_authentication_response
from webauthn.helpers import base64url_to_bytes
from webauthn.helpers import base64url_to_bytes, parse_authentication_credential_json
from webauthn.helpers.exceptions import InvalidAuthenticationResponse
from webauthn.helpers.structs import AuthenticationCredential


class TestVerifyAuthenticationResponse(TestCase):
def test_verify_authentication_response_with_EC2_public_key(self):
credential = AuthenticationCredential.parse_raw(
"""{
credential = """{
"id": "EDx9FfAbp4obx6oll2oC4-CZuDidRVV4gZhxC529ytlnqHyqCStDUwfNdm1SNHAe3X5KvueWQdAX3x9R1a2b9Q",
"rawId": "EDx9FfAbp4obx6oll2oC4-CZuDidRVV4gZhxC529ytlnqHyqCStDUwfNdm1SNHAe3X5KvueWQdAX3x9R1a2b9Q",
"response": {
Expand All @@ -20,7 +18,6 @@ def test_verify_authentication_response_with_EC2_public_key(self):
"type": "public-key",
"clientExtensionResults": {}
}"""
)
challenge = base64url_to_bytes(
"xi30GPGAFYRxVDpY1sM10DaLzVQG66nv-_7RUazH0vI2YvG8LYgDEnvN5fZZNVuvEDuMi9te3VLqb42N0fkLGA"
)
Expand Down Expand Up @@ -48,20 +45,18 @@ def test_verify_authentication_response_with_EC2_public_key(self):
assert verification.credential_device_type == 'single_device'

def test_verify_authentication_response_with_RSA_public_key(self):
credential = AuthenticationCredential.parse_raw(
"""{
"id": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"rawId": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"response": {
"authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAAAQ",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaVBtQWkxUHAxWEw2b0FncTNQV1p0WlBuWmExekZVRG9HYmFRMF9LdlZHMWxGMnMzUnRfM280dVN6Y2N5MHRtY1RJcFRUVDRCVTFULUk0bWFhdm5kalEiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
"signature": "iOHKX3erU5_OYP_r_9HLZ-CexCE4bQRrxM8WmuoKTDdhAnZSeTP0sjECjvjfeS8MJzN1ArmvV0H0C3yy_FdRFfcpUPZzdZ7bBcmPh1XPdxRwY747OrIzcTLTFQUPdn1U-izCZtP_78VGw9pCpdMsv4CUzZdJbEcRtQuRS03qUjqDaovoJhOqEBmxJn9Wu8tBi_Qx7A33RbYjlfyLm_EDqimzDZhyietyop6XUcpKarKqVH0M6mMrM5zTjp8xf3W7odFCadXEJg-ERZqFM0-9Uup6kJNLbr6C5J4NDYmSm3HCSA6lp2iEiMPKU8Ii7QZ61kybXLxsX4w4Dm3fOLjmDw",
"userHandle": "T1RWa1l6VXdPRFV0WW1NNVlTMDBOVEkxTFRnd056Z3RabVZpWVdZNFpEVm1ZMk5p"
},
"type": "public-key",
"clientExtensionResults": {}
}"""
)
credential = """{
"id": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"rawId": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"response": {
"authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAAAQ",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaVBtQWkxUHAxWEw2b0FncTNQV1p0WlBuWmExekZVRG9HYmFRMF9LdlZHMWxGMnMzUnRfM280dVN6Y2N5MHRtY1RJcFRUVDRCVTFULUk0bWFhdm5kalEiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
"signature": "iOHKX3erU5_OYP_r_9HLZ-CexCE4bQRrxM8WmuoKTDdhAnZSeTP0sjECjvjfeS8MJzN1ArmvV0H0C3yy_FdRFfcpUPZzdZ7bBcmPh1XPdxRwY747OrIzcTLTFQUPdn1U-izCZtP_78VGw9pCpdMsv4CUzZdJbEcRtQuRS03qUjqDaovoJhOqEBmxJn9Wu8tBi_Qx7A33RbYjlfyLm_EDqimzDZhyietyop6XUcpKarKqVH0M6mMrM5zTjp8xf3W7odFCadXEJg-ERZqFM0-9Uup6kJNLbr6C5J4NDYmSm3HCSA6lp2iEiMPKU8Ii7QZ61kybXLxsX4w4Dm3fOLjmDw",
"userHandle": "T1RWa1l6VXdPRFV0WW1NNVlTMDBOVEkxTFRnd056Z3RabVZpWVdZNFpEVm1ZMk5p"
},
"type": "public-key",
"clientExtensionResults": {}
}"""
challenge = base64url_to_bytes(
"iPmAi1Pp1XL6oAgq3PWZtZPnZa1zFUDoGbaQ0_KvVG1lF2s3Rt_3o4uSzccy0tmcTIpTTT4BU1T-I4maavndjQ"
)
Expand All @@ -85,8 +80,7 @@ def test_verify_authentication_response_with_RSA_public_key(self):
assert verification.new_sign_count == 1

def test_raises_exception_on_incorrect_public_key(self):
credential = AuthenticationCredential.parse_raw(
"""{
credential = """{
"id": "FviUBZA3FGMxEm3A1K2T8MhuEBLp4qQsV9ScAKYrpdw2kbGnqx24tF4ev6PEHEYC3g8z6HMJh7dYHe3Uuq7_8Q",
"rawId": "FviUBZA3FGMxEm3A1K2T8MhuEBLp4qQsV9ScAKYrpdw2kbGnqx24tF4ev6PEHEYC3g8z6HMJh7dYHe3Uuq7_8Q",
"response": {
Expand All @@ -97,7 +91,6 @@ def test_raises_exception_on_incorrect_public_key(self):
"type": "public-key",
"clientExtensionResults": {}
}"""
)
challenge = base64url_to_bytes(
"zsfiMZj16TUVCrT5tDRYXdYlUrJp7zn_UNd5NmBocPc4I2dKZbeEWpwBAwA4s6oHkVX6_ly_jgp743dyiWHYYw"
)
Expand All @@ -123,8 +116,7 @@ def test_raises_exception_on_incorrect_public_key(self):
)

def test_raises_exception_on_uv_required_but_false(self):
credential = AuthenticationCredential.parse_raw(
"""{
credential = """{
"id": "4-5MZF69j3n2B6Z99dUN0fNrAQmrjELJIebWVw8aKfw1EQKg28Tx40R_kw-1pcrfSgJFKm3mCtAtBgSRWgDMng",
"rawId": "4-5MZF69j3n2B6Z99dUN0fNrAQmrjELJIebWVw8aKfw1EQKg28Tx40R_kw-1pcrfSgJFKm3mCtAtBgSRWgDMng",
"response": {
Expand All @@ -135,7 +127,6 @@ def test_raises_exception_on_uv_required_but_false(self):
"type": "public-key",
"clientExtensionResults": {}
}"""
)
challenge = base64url_to_bytes(
"umGemXJIPBXPxkD8Hjanuv9BDor8Z7O3aPdtOgMCdW4PAfqDX43EFlhrsF0PW90df5zrgbt7YVMRAa27tCdHzw"
)
Expand All @@ -161,19 +152,17 @@ def test_raises_exception_on_uv_required_but_false(self):
)

def test_verify_authentication_response_with_OKP_public_key(self):
credential = AuthenticationCredential.parse_raw(
"""{
"id": "fq9Nj0nS24B5y6Pkw_h3-9GEAEA3-0LBPxE2zvTdLjDqtSeCSNYFe9VMRueSpAZxT3YDc6L1lWXdQNwI-sVNYrefEcRR1Nsb_0jpHE955WEtFud2xxZg3MvoLMxHLet63i5tajd1fHtP7I-00D6cehM8ZWlLp2T3s9lfZgVIFcA",
"rawId": "fq9Nj0nS24B5y6Pkw_h3-9GEAEA3-0LBPxE2zvTdLjDqtSeCSNYFe9VMRueSpAZxT3YDc6L1lWXdQNwI-sVNYrefEcRR1Nsb_0jpHE955WEtFud2xxZg3MvoLMxHLet63i5tajd1fHtP7I-00D6cehM8ZWlLp2T3s9lfZgVIFcA",
"response": {
"authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MBAAAABw",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiZVo0ZWVBM080ank1Rkl6cURhU0o2SkROR3UwYkJjNXpJMURqUV9rTHNvMVdOcWtHNms1bUNZZjFkdFFoVlVpQldaV2xaa3pSNU1GZWVXQ3BKUlVOWHciLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
"signature": "RRWV8mYDRvK7YdQgdtZD4pJ2dh1D_IWZ_D6jsZo6FHJBoenbj0CVT5nA20vUzlRhN4R6dOEUHmUwP1F8eRBhBg"
},
"type": "public-key",
"clientExtensionResults": {}
}"""
)
credential = """{
"id": "fq9Nj0nS24B5y6Pkw_h3-9GEAEA3-0LBPxE2zvTdLjDqtSeCSNYFe9VMRueSpAZxT3YDc6L1lWXdQNwI-sVNYrefEcRR1Nsb_0jpHE955WEtFud2xxZg3MvoLMxHLet63i5tajd1fHtP7I-00D6cehM8ZWlLp2T3s9lfZgVIFcA",
"rawId": "fq9Nj0nS24B5y6Pkw_h3-9GEAEA3-0LBPxE2zvTdLjDqtSeCSNYFe9VMRueSpAZxT3YDc6L1lWXdQNwI-sVNYrefEcRR1Nsb_0jpHE955WEtFud2xxZg3MvoLMxHLet63i5tajd1fHtP7I-00D6cehM8ZWlLp2T3s9lfZgVIFcA",
"response": {
"authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MBAAAABw",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiZVo0ZWVBM080ank1Rkl6cURhU0o2SkROR3UwYkJjNXpJMURqUV9rTHNvMVdOcWtHNms1bUNZZjFkdFFoVlVpQldaV2xaa3pSNU1GZWVXQ3BKUlVOWHciLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
"signature": "RRWV8mYDRvK7YdQgdtZD4pJ2dh1D_IWZ_D6jsZo6FHJBoenbj0CVT5nA20vUzlRhN4R6dOEUHmUwP1F8eRBhBg"
},
"type": "public-key",
"clientExtensionResults": {}
}"""
challenge = base64url_to_bytes(
"eZ4eeA3O4jy5FIzqDaSJ6JDNGu0bBc5zI1DjQ_kLso1WNqkG6k5mCYf1dtQhVUiBWZWlZkzR5MFeeWCpJRUNXw"
)
Expand All @@ -196,8 +185,7 @@ def test_verify_authentication_response_with_OKP_public_key(self):
assert verification.new_sign_count == 7

def test_supports_multiple_expected_origins(self) -> None:
credential = AuthenticationCredential.parse_raw(
"""{
credential = """{
"id": "AXmOjWWZH67pgl5_gAbKVBqoL2dyHHGEWZLspIsCwULG0hZ3HyuGgvkaRcSOLq9W72XtegcvFYXIdlafrilbtVnx2Q14gNbfSQQP2sgNEAif4MjHtGpeVB0BfFawCs85Y3XY_j4sxthVnyTY_Q",
"rawId": "AXmOjWWZH67pgl5_gAbKVBqoL2dyHHGEWZLspIsCwULG0hZ3HyuGgvkaRcSOLq9W72XtegcvFYXIdlafrilbtVnx2Q14gNbfSQQP2sgNEAif4MjHtGpeVB0BfFawCs85Y3XY_j4sxthVnyTY_Q",
"response": {
Expand All @@ -209,7 +197,6 @@ def test_supports_multiple_expected_origins(self) -> None:
"type": "public-key",
"clientExtensionResults": {}
}"""
)

challenge = base64url_to_bytes(
"6zrSRX8CxwPSXEArXyXL2tpb6rB7Star0rLVIj5rvf74mZKF5ir715Xmgz5tA_GyHexN4oXfrQ889ArVCLaRdA"
Expand All @@ -233,3 +220,38 @@ def test_supports_multiple_expected_origins(self) -> None:
assert verification.credential_id == base64url_to_bytes(
"AXmOjWWZH67pgl5_gAbKVBqoL2dyHHGEWZLspIsCwULG0hZ3HyuGgvkaRcSOLq9W72XtegcvFYXIdlafrilbtVnx2Q14gNbfSQQP2sgNEAif4MjHtGpeVB0BfFawCs85Y3XY_j4sxthVnyTY_Q"
)

def test_supports_already_parsed_credential(self) -> None:
parsed_credential = parse_authentication_credential_json("""{
"id": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"rawId": "ZoIKP1JQvKdrYj1bTUPJ2eTUsbLeFkv-X5xJQNr4k6s",
"response": {
"authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFAAAAAQ",
"clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiaVBtQWkxUHAxWEw2b0FncTNQV1p0WlBuWmExekZVRG9HYmFRMF9LdlZHMWxGMnMzUnRfM280dVN6Y2N5MHRtY1RJcFRUVDRCVTFULUk0bWFhdm5kalEiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjUwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
"signature": "iOHKX3erU5_OYP_r_9HLZ-CexCE4bQRrxM8WmuoKTDdhAnZSeTP0sjECjvjfeS8MJzN1ArmvV0H0C3yy_FdRFfcpUPZzdZ7bBcmPh1XPdxRwY747OrIzcTLTFQUPdn1U-izCZtP_78VGw9pCpdMsv4CUzZdJbEcRtQuRS03qUjqDaovoJhOqEBmxJn9Wu8tBi_Qx7A33RbYjlfyLm_EDqimzDZhyietyop6XUcpKarKqVH0M6mMrM5zTjp8xf3W7odFCadXEJg-ERZqFM0-9Uup6kJNLbr6C5J4NDYmSm3HCSA6lp2iEiMPKU8Ii7QZ61kybXLxsX4w4Dm3fOLjmDw",
"userHandle": "T1RWa1l6VXdPRFV0WW1NNVlTMDBOVEkxTFRnd056Z3RabVZpWVdZNFpEVm1ZMk5p"
},
"type": "public-key",
"clientExtensionResults": {}
}""")
challenge = base64url_to_bytes(
"iPmAi1Pp1XL6oAgq3PWZtZPnZa1zFUDoGbaQ0_KvVG1lF2s3Rt_3o4uSzccy0tmcTIpTTT4BU1T-I4maavndjQ"
)
expected_rp_id = "localhost"
expected_origin = "http://localhost:5000"
credential_public_key = base64url_to_bytes(
"pAEDAzkBACBZAQDfV20epzvQP-HtcdDpX-cGzdOxy73WQEvsU7Dnr9UWJophEfpngouvgnRLXaEUn_d8HGkp_HIx8rrpkx4BVs6X_B6ZjhLlezjIdJbLbVeb92BaEsmNn1HW2N9Xj2QM8cH-yx28_vCjf82ahQ9gyAr552Bn96G22n8jqFRQKdVpO-f-bvpvaP3IQ9F5LCX7CUaxptgbog1SFO6FI6ob5SlVVB00lVXsaYg8cIDZxCkkENkGiFPgwEaZ7995SCbiyCpUJbMqToLMgojPkAhWeyktu7TlK6UBWdJMHc3FPAIs0lH_2_2hKS-mGI1uZAFVAfW1X-mzKL0czUm2P1UlUox7IUMBAAE"
)
sign_count = 0

verification = verify_authentication_response(
credential=parsed_credential,
expected_challenge=challenge,
expected_rp_id=expected_rp_id,
expected_origin=expected_origin,
credential_public_key=credential_public_key,
credential_current_sign_count=sign_count,
require_user_verification=True,
)

assert verification.new_sign_count == 1
Loading

0 comments on commit 6ac0f9d

Please sign in to comment.