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.7, 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.

Listing connected YubiKeys

The first step you’ll likely want to do is to list currently connected YubiKeys, and get some information about them. This is what the list_all_devices function is for. It detects and connects to each attached YubiKey, reading some information about it. It returns a list of tuples consisting of a YubiKeyDevice and a corresponding DeviceInfo. The DeviceInfo can tell you what kind of YubiKey it is, what capabilities it has, its serial number, etc. The YubiKeyDevice will let you open a Connection to it, which will let you interact with one of the available Applications.

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 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
        print(f"Found YubiKey with serial number: {info.serial}")

Connecting to a YubiKey

To actually do anything with a YubiKey you’ll need to create a Connection and 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. Once you have a reference to a YubiKeyDevice you can call the open_connection method on it to open a Connection of a specific type. There are three different types of Connections, used for different Applications. These are SmartCardConnection, OtpConnection and FidoConnection. 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 list_all_devices
from yubikit.core.smartcard import SmartCardConnection
from yubikit.piv import PivSession

# Select a connected YubiKeyDevice
dev, info = list_all_devices()[0]

# Connect to a YubiKey over a SmartCardConnection, which is needed for PIV.
with dev.open_connection(SmartCardConnection) as connection:
    # The connection will be automatically closed after this block

    piv = PivSession(connection)
    attempts = piv.get_pin_attempts()
    print(f"You have {attempts} PIN attempts left.")

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 list_all_devices, scan_devices
from yubikit.core.smartcard import SmartCardConnection
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}")
                ...  # Do something with the device here.
                handled_serials.add(info.serial)
    else:
        sleep(1.0)  # No change, sleep for 1 second.