U2F Host Library
pyu2f is a Python-based U2F host library for Linux, Windows, and MacOS, providing functionality for interacting with U2F devices over USB. The current version is 0.1.5. The library's support is discontinued as U2F is an outdated FIDO specification, with `python-fido2` being the recommended alternative for FIDO2 and U2F backward compatibility.
Common errors
-
ModuleNotFoundError: No module named 'pyu2f'
cause The `pyu2f` package is not installed in the current Python environment or the environment is not activated.fixRun `pip install pyu2f` to install the library. Ensure your Python environment is correctly activated if using virtual environments. -
OSError: [WinError 50] This request is not supported.
cause This error typically occurs on Windows, specifically within `pyu2f.hid.windows.FillDeviceAttributes`, when attempting to call `HidD_GetProductString` during HID device enumeration. It suggests a low-level interaction issue with the Windows HID API, potentially due to specific device drivers or Windows versions.fixThis issue is complex and may not have a simple direct fix within `pyu2f`. Consider updating Windows drivers, testing on different Windows versions, or, preferably, migrating to `python-fido2` for more robust and actively maintained hardware interaction. -
TypeError: argument of type 'bytes' is not iterable
cause This error can occur in Python 3 when a function expects an iterable (like a string) but receives bytes, often due to incorrect handling of `bytes` vs. `str` differences, especially during decoding/encoding operations that changed between Python 2 and 3.fixExplicitly decode byte strings (`.decode('utf-8')`) when a string is expected, or encode strings (`.encode('utf-8')`) when bytes are expected, ensuring consistent handling of text data.
Warnings
- breaking The `pyu2f` library is officially discontinued and no longer supported. Users are strongly advised to migrate to `Yubico/python-fido2`, which supports both FIDO2 and is backward compatible with U2F devices. Continued use of `pyu2f` may lead to unaddressed security vulnerabilities or compatibility issues.
- deprecated The underlying U2F API in web browsers (e.g., Chrome) has been deprecated in favor of the WebAuthn API. While WebAuthn is backward compatible with U2F devices, this deprecation affects how web applications initiate U2F interactions. Although `pyu2f` is a host library, this trend highlights the obsolescence of the U2F standard itself.
- gotcha On Windows 10, users might encounter an `OSError: [WinError 50] This request is not supported.` (or similar) when `pyu2f` attempts to enumerate HID devices via `HidD_GetProductString`. This can prevent U2F devices from being detected or used.
- breaking Versions prior to 0.1.2 lacked Python 3 support, and version 0.1.3 replaced `python-future` with `six` for Python 2/3 compatibility. Code written for older Python 2 versions or relying on `python-future` might break or behave unexpectedly in newer Python environments or with `pyu2f` versions 0.1.3 and later.
Install
-
pip install pyu2f
Imports
- model
from pyu2f import model
- authenticator
from pyu2f.convenience import authenticator
Quickstart
import os
from pyu2f import model
from pyu2f.convenience import authenticator
# --- Placeholder values for demonstration ---
# In a real application, these would come from a U2F challenge
# issued by a relying party (e.g., a web service).
APP_ID = 'https://example.com'
ORIGIN = 'https://example.com'
CHALLENGE_BASE64 = 'some_base64_challenge_data_from_server'
KEY_HANDLE_BASE64 = 'some_base64_key_handle_from_previous_registration'
print("Attempting U2F authentication...")
try:
# 1. Prepare registered key and challenge data
# The RegisteredKey model requires a base64 encoded key handle.
registered_key = model.RegisteredKey(KEY_HANDLE_BASE64.encode('utf-8'))
# The challenge data is a list of dictionaries, each containing
# a RegisteredKey object and the raw challenge.
challenge_data = [{
'key': registered_key,
'challenge': CHALLENGE_BASE64.encode('utf-8')
}]
# 2. Create the authenticator interface
api = authenticator.CreateCompositeAuthenticator(ORIGIN)
# 3. Authenticate with the U2F device
# This will typically prompt the user to touch their security key.
response = api.Authenticate(APP_ID, challenge_data)
if response:
print("Authentication successful!")
print(f"Client Data: {response.client_data.decode('utf-8')}")
print(f"Signature Data: {response.signature_data.decode('utf-8')}")
else:
print("Authentication failed or timed out.")
except Exception as e:
print(f"An error occurred during authentication: {e}")
# Optional: Using a custom authenticator plugin via environment variable
# SK_SIGNING_PLUGIN = '/path/to/your/custom_authenticator_script.py'
# os.environ['SK_SIGNING_PLUGIN'] = SK_SIGNING_PLUGIN
# print(f"Custom authenticator plugin set: {os.environ.get('SK_SIGNING_PLUGIN')}")
# Then call Authenticate again. The plugin script must adhere to
# the specification in customauthenticator.py (refer to source code).