Skip to content

Instantly share code, notes, and snippets.

@joostd
Last active January 23, 2026 12:09
Show Gist options
  • Select an option

  • Save joostd/16970c2b06be71767d02ab458b41251c to your computer and use it in GitHub Desktop.

Select an option

Save joostd/16970c2b06be71767d02ab458b41251c to your computer and use it in GitHub Desktop.
Tap and go with a FIDO security key
"""
Register a resident FIDO credential, using USB
Insert a FIDO2 security key in a USB port, and run with:
ykman script register.py
"""
from fido2.hid import CtapHidDevice
from fido2.ctap2 import Ctap2, ClientPin
from fido2.utils import sha256, hmac_sha256
from secrets import token_bytes
pin = "123456"
devices = list(CtapHidDevice.list_devices())
if not devices:
print("No devices found")
exit()
ctap = Ctap2(devices[0])
client_data_hash = sha256(token_bytes(32))
client_pin = ClientPin(ctap)
pin_token = client_pin.get_pin_token(pin)
pin_auth = hmac_sha256(pin_token, client_data_hash)
attestation_object = ctap.make_credential(
client_data_hash,
rp = {"id": "example.com", "name": "Example"},
user = {"id": b"user_id", "name": "user", "displayName": "user" },
key_params = [{"type": "public-key", "alg": -7}],
pin_uv_param=pin_auth,
pin_uv_protocol=2,
options = {"rk": True}
)
# save somewhere for future authentication
print("Credential ID: ", bytes.hex(attestation_object.auth_data.credential_data.credential_id))
print("Public Key: ", attestation_object.auth_data.credential_data.public_key)
"""
Tap & Go - Authenticate a resident FIDO credential, using NFC
Connect an NFC reader, and run with:
ykman script tapandgo.py
"""
from fido2.ctap2 import ClientPin
from fido2.utils import sha256
import json
from fido2.ctap2 import Ctap2
from fido2.utils import hmac_sha256
from fido2.pcsc import CtapPcscDevice
from time import sleep
from secrets import token_bytes
while True:
devices = list(CtapPcscDevice.list_devices())
if devices:
break
print("No devices found: tap your security key")
sleep(1)
ctap = Ctap2(devices[0])
client_data_hash = sha256(token_bytes(32))
assertion_object = ctap.get_assertion(
"example.com",
client_data_hash,
)
# skipped: check user/credential IDs and verify signature using corresponding public key
print("credential ID: ", bytes.hex(assertion_object.credential['id']))
print("signature:", bytes.hex(assertion_object.signature))
print("user ID: ", assertion_object.user['id'].decode())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment