Server side handlers for WebAuthN with support for Apple's FaceID, and the FIDO metadata service.
A small Flask app showcasing this library is provided in the demo folder.
Part 1: generate request to be sent to browser
# User the credential is to be registered touser=webauthn.types.User(
id=b"test",
display_name="Test user",
name="test@example.com",
icon=None
)
# Who is requesting the credentialrp=webauthn.types.RelyingParty(
id="as207960-webauthn.eu.ngrok.io",
name="AS207960",
icon="https://as207960.net/assets/img/logo.svg"
)
data, challenge=webauthn.create_webauthn_credentials(
rp=rp, user=user, existing_keys=[],
attachment=None, require_resident=False,
user_verification=webauthn.types.UserVerification.Preferred,
attestation_request=webauthn.types.Attestation.DirectAttestation,
)
# Store the challenge and user for part 3Part 2: Create credential through the browser
functionb64decode(input){returnUint8Array.from(window.atob(input),c=>c.charCodeAt(0));}functionb64encode(input){returnwindow.btoa(String.fromCharCode.apply(null,newUint8Array(input)));}// Data having already been retrieved from the serverdata.user.id=b64decode(data.user.id);data.challenge=b64decode(data.challenge);data.excludeCredentials=data.excludeCredentials.map(function(cred){cred.id=b64decode(cred.id);returncred;})navigator.credentials.create({publicKey: data}).then(function(response){letdata={id: b64encode(response.rawId),response: {data: b64encode(response.response.clientDataJSON),attestation: b64encode(response.response.attestationObject),}}// Send response data back to the server});Part 3: Complete registration on the server
# Response is the data from the browser as above# This should be cachedfido_metadata=webauthn.metadata.get_metadata()
auth_data=webauthn.verify_create_webauthn_credentials(
rp=rp, challenge_b64=challenge,
client_data_b64=response["data"],
attestation_b64=response["attestation"],
fido_metadata=fido_metadata
)The auth_data response can be inspected to decide if the authenticator is to be allowed by the server. Such rules are
outside the scope of this package.
Part 1: generate request to be sent to browser
options, challenge=webauthn.get_webauthn_credentials(
rp=rp,
existing_keys=[pkey_id],
user_verification=webauthn.types.UserVerification.Preferred,
)
# Store the challenge and user for part 3Part 2: Sign challenge
// Data having already been retrieved from the serverdata.challenge=b64decode(data.challenge);data.allowCredentials=data.allowCredentials.map(function(cred){cred.id=b64decode(cred.id);returncred;})returnnavigator.credentials.get({publicKey: data}).then(function(response){letdata={response: {data: b64encode(response.response.clientDataJSON),authenticator: b64encode(response.response.authenticatorData),signature: b64encode(response.response.signature),user: b64encode(response.response.userHandle),}}// Send response data back to the server});Part 3: Verify response on the server
# Response is the data from the browser as above# This should be cachedfido_metadata=webauthn.metadata.get_metadata()
auth_data=webauthn.verify_create_webauthn_credentials(
rp=rp, challenge_b64=challenge,
client_data_b64=response["data"],
attestation_b64=response["attestation"],
fido_metadata=fido_metadata
)