Using ykman as a Python library

In addition to using ykman as a standalone command line application, you can also use this project as a Python library for scripting purposes.

Setup

You will need to have Python >= 3.6, and have yubikey-manager installed and added to your PYTHON_PATH. You can verify that this is set up correctly by running the following command from a Terminal:

python -c "import ykman"

If the above runs without error (no output at all), then you should be all set.

Connecting to a YubiKey

The first step you’ll likely want to do is to establish a Session with a YubiKey Application. Depending on which Application you intend to access, you’ll need to establish a specific type of Connection. The connect_to_device function lets you search for, and connect to, a YubiKey. Once you are done using a Connection, you should close it. This can be done explicitly by calling connection.close(), or by using a with block.

Example

from ykman.device import connect_to_device
from yubikit.core.smartcard import SmartCardConnection
from yubikit.piv import PivSession

# Connect to a YubiKey over a SmartCardConnection, which is needed for PIV.
connection, device, info = connect_to_device(
    serial=123456,  # Serial number of the YubiKey to connect to, can be omitted
    connection_types=[SmartCardConnection],  # Possible Connection types to allow
)

with connection:  # This closes the connection after the block
    piv = PivSession(connection)
    attempts = piv.get_pin_attempts()
    print(f"You have {attempts} PIN attempts left.")

Listing all connected YubiKeys

Just using connect_to_device allows you to connect to a single YubiKey, either by specifying its serial number, or by only having a single YubiKey connected. When working with multiple connected YubiKeys you’ll likely find a need for enumerating these. You can use list_all_devices for this purpose.

Note

list_all_devices connects to each detected YubiKey to read out some information. This will interrupt any already-established connections! See scan_devices for a an alternative which does not interrupt existing connections.

Example

from ykman.device import connect_to_device, list_all_devices
from yubikit.core.smartcard import SmartCardConnection

for device, info in list_all_devices():
    if info.version >= (5, 0, 0):  # The info object provides details about the YubiKey
        connection, _, _ = connect_to_device(serial=info.serial, connection_types=[SmartCardConnection])
        with connection:
            ...  # Do something with the connection.

Detecting YubiKey insertion

Sometimes you’ll want to do something when a YubiKey is inserted. You can use the scan_devices function to poll for changes to the connected YubiKeys, without interrupting any ongoing connections. It returns a dict of PIDs (Product Identifiers) mapped to the number of connected devices for each PID, as well as a state parameter which will change if the configuration of connected YubiKeys changes.

Example

from ykman.device import connect_to_device, list_all_devices, scan_devices
from time import sleep

handled_serials = set()  # Keep track of YubiKeys we've already handled.
state = None

while True:  # Run this until we stop the script with Ctrl+C
    pids, new_state = scan_devices()
    if new_state != state:
        state = new_state  # State has changed
        for device, info in list_all_devices():
            if info.serial not in handled_serials:  # Unhandled YubiKey
                print(f"Programming YubiKey with serial: {info.serial}")
                # Since we're not filtering on connection type here the Connection may have any type.
                with connect_to_device(info.serial)[0] as connection:
                    ...  # Do something with the connection.
                handled.add(info.serial)
    else:
        sleep(1.0)  # No change, sleep for 1 second.