Registration¶
WebAuthn registration ceremonies can be broken up into two operations:
Generate WebAuthn API options
Verify the WebAuthn response
Typical use of WebAuthn requires that a user account be identified at the time of registration. This can mean:
The user has successfully logged in via username and password and is proceeding through a prompt to upgrade to using passkeys
The user has just clicked a magic link to confirm their email address during new account creation
A logged-in user is adding a passkey to go passwordless on their next login
Regardless of the scenario, the Relying Party should ensure they have a strong sense of which user is logged in before proceeding.
Generate Options¶
Registration options are created using the following method:
from webauthn import generate_registration_options
from webauthn.helpers.structs import (
AttestationConveyancePreference,
AuthenticatorAttachment,
AuthenticatorSelectionCriteria,
PublicKeyCredentialDescriptor,
ResidentKeyRequirement,
)
from webauthn.helpers.cose import COSEAlgorithmIdentifier
# Simple Options
simple_registration_options = generate_registration_options(
rp_id="example.com",
rp_name="Example Co",
user_name="bob",
)
# Complex Options
complex_registration_options = generate_registration_options(
rp_id="example.com",
rp_name="Example Co",
user_id=bytes([1, 2, 3, 4]),
user_name="Lee",
attestation=AttestationConveyancePreference.DIRECT,
authenticator_selection=AuthenticatorSelectionCriteria(
authenticator_attachment=AuthenticatorAttachment.PLATFORM,
resident_key=ResidentKeyRequirement.REQUIRED,
),
challenge=bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]),
exclude_credentials=[
PublicKeyCredentialDescriptor(
id=b"1234567890",
transports=[
AuthenticatorTransport.INTERNAL,
AuthenticatorTransport.HYBRID,
]
),
],
supported_pub_key_algs=[COSEAlgorithmIdentifier.ECDSA_SHA_512],
timeout=12000,
)
See the docstrings for details about the various required and optional kwargs.
The output from generate_registration_options()
can be passed into webauthn.helpers.options_to_json()
to quickly convert them to a str
value that can be sent to the browser as JSON.
Tip
If you are using @simplewebauthn/browser in your front end code then you can pass…
opts = options_to_json(
generate_registration_options(**kwargs)
)
…directly into its startRegistration(opts)
method.
Verify Response¶
Registration responses can be verified using the following method:
from webauthn import (
verify_registration_response, # <--
base64url_to_bytes,
)
verification = verify_registration_response(
# Can be a `str` or `dict`
credential={
"id": "...",
"rawId": "...",
"response": {
"attestationObject": "...",
"clientDataJSON": "...",
"transports": ["internal"],
},
"type": "public-key",
"clientExtensionResults": {},
"authenticatorAttachment": "platform",
},
# The value of `options.challenge` from above
expected_challenge=base64url_to_bytes("..."),
expected_rp_id="example.com",
expected_origin="https://example.com",
require_user_verification=True,
)
See the docstrings for details about the various required and optional kwargs.
Tip
If you are using @simplewebauthn/browser in your front end code then you can pass the output from startRegistration(opts)
directly into verify_registration_response(**kwargs)
as the credential
kwarg.
After verifying a response, store the following values from verification
above for the logged-in user in the database so that they can use this passkey later to sign in:
verification.credential_id
verification.credential_public_key
verification.sign_count
verification.credential_device_type
verification.credential_backed_up
credential["response"]["transports"]