Skip to main content

Python KSeF Authentication Library (for PKCS#11 and local private keys)

(PL) Opis

Biblioteka do Pythona implementująca logowanie do Krajowego Systemu e-Faktur (KSeF) z użyciem dowolnego klucza prywatnego obsługującego interfejs PKCS#11. Obsługuje kwalifikowane podpisy i pieczęci elektroniczne w dowolnej postaci (na karcie, tokenie USB lub w formie HSM), a także certyfikaty wydane przez KSeF, do których klucze prywatne przechowywane są na HSMie (np. YubiHSM, YubiKey, Google Cloud KMS). Biblioteka wspiera również klasyczne uwierzytelnianie kluczem przechowywanym lokalnie na dysku twardym w pliku .key (format PEM).

Supported features

  • Authentication using private keys available through PKCS#11 interface:
    • Qualified signature or qualified seal issued on a physical device,
    • KSeF Certificate hosted on a HSM (e.g. YubiHSM, YubiKey, Google Cloud KMS).
  • Authentication using certificate and private key stored as PEM files on local hard disk.

Installation

Library available on PyPi: pyksef

pip3 install pyksef

Usage via Python

List tokens available with certain PKCS#11 provider

from pyksef.p11 import PKCS11Lib

# load PKCS#11 library for CryptoCard Graphite (note that any qualified signature/seal issuer is supported)
PKCS11_DLL_PATH = "C:\\Program Files\\Krajowa Izba Rozliczeniowa S.A\\Szafir 2.0\\bin\\CCGraphiteP11p.x64.dll"

lib = PKCS11Lib(PKCS11_DLL_PATH)
for token in lib.get_tokens():
    print(token)

Example output:

TokenRecord(slot=<Slot (slotID=2 flags=7)>, label='PKI Token 1 (Primary)', serial='31333132303030313233343536373839', manufacturer_id='CryptoTech P.S.A.', model='CCGraphitePro', hardware_version=(0, 0), firmware_version=(0, 0), flags=<TokenFlag.LOGIN_REQUIRED|USER_PIN_INITIALIZED|TOKEN_INITIALIZED: 1036>)
TokenRecord(slot=<Slot (slotID=3 flags=7)>, label='PKI Token 2 (QSCD)', serial='31333132303030313233343536373839', manufacturer_id='CryptoTech P.S.A.', model='CCGraphitePro', hardware_version=(0, 0), firmware_version=(0, 0), flags=<TokenFlag.WRITE_PROTECTED|LOGIN_REQUIRED|USER_PIN_INITIALIZED|TOKEN_INITIALIZED: 1038>)

List private keys/certificates available with certain PKCS#11 token

import getpass

from pyksef.p11 import PKCS11Lib

PKCS11_DLL_PATH = "C:\\Program Files\\Krajowa Izba Rozliczeniowa S.A\\Szafir 2.0\\bin\\CCGraphiteP11p.x64.dll"
TOKEN_LABEL = "PKI Token 2 (QSCD)"
USER_PIN = getpass.getpass("User PIN: ")

lib = PKCS11Lib(PKCS11_DLL_PATH)
lib.set_token(token_label=TOKEN_LABEL, user_pin=USER_PIN)

for certificate in lib.get_certificates():
    print(certificate)

for private_key in lib.get_private_keys():
    print(private_key)

Example output:

CertificateRecord(x509_cert=<Certificate(subject=<Name(C=PL,2.5.4.5=PNOPL-12345678900,CN=Jan Kowalski,2.5.4.42=Jan,2.5.4.4=Kowalski)>, ...)>)
PrivateKeyRecord(label='No Friendly Name Available', id='6572df736d642974a2bab6ddba753aefb89afcce', key_type=<KeyType.RSA>)

KSeF XAdES Authentication

Using a private key available over PKCS#11

import binascii
import getpass
import json

from pyksef import ksef_auth_xades
from pyksef.auth.identifier import ContextIdentifier, ContextIdentifierType, SubjectIdentifierType
from pyksef.auth.state import ksef_poll_auth_finalized
from pyksef.p11 import create_p11_private_key, PKCS11Lib, get_leaf_certificate
from pyksef.x509 import load_pem_x509_certificate


# PKCS#11 Token parameters
PKCS11_DLL_PATH = "C:\\Program Files\\Krajowa Izba Rozliczeniowa S.A\\Szafir 2.0\\bin\\CCGraphiteP11p.x64.dll"
TOKEN_LABEL = "PKI Token 2 (QSCD)"
USER_PIN = getpass.getpass("User PIN: ")
PRIVATE_KEY_ID = "6572df736d642974a2bab6ddba753aefb89afcce"

# Authentication parameters
CONTEXT_ID = ContextIdentifier(type=ContextIdentifierType.nip, value="5421234567")
SUBJECT_ID_TYPE = SubjectIdentifierType.certificateSubject

# API URL
PROD_API_BASE_URL = "https://api.ksef.mf.gov.pl/v2"

# ---

lib = PKCS11Lib(PKCS11_DLL_PATH)
lib.set_token(token_label=TOKEN_LABEL, user_pin=USER_PIN)
lib.set_private_key(key_id=binascii.unhexlify(PRIVATE_KEY_ID))

# download the signer's certificate from the signer device directly
cert = get_leaf_certificate(o.x509_cert for o in lib.get_certificates())

# alternatively, you may just read the signer's certificate from file
# ---
# with open("ksef.crt", "rb") as f:
#     cert = load_pem_x509_certificate(cert_pem_bytes)
# ---

# perform KSeF authentication using PKCS#11 private key
auth_res = ksef_auth_xades(
  api_base_url=PROD_API_BASE_URL,
  cert=cert,
  key=create_p11_private_key(lib, cert),
  context_id=CONTEXT_ID,
  subject_id_type=SUBJECT_ID_TYPE,
)

# poll authentication state and redeem the actual token
# we may need to wait a little bit before the authentication is approved
auth_state = ksef_poll_auth_finalized(
    api_base_url=PROD_API_BASE_URL,
    reference_number=auth_res["referenceNumber"],
    authentication_token=auth_res["authenticationToken"]["token"]
)

print(json.dumps({
    "ksefAuthInitResult": auth_res,
    "ksefPollAuthFinalizedResult": auth_state,
}, indent=4))

Using private key available as PEM file locally on the hard disk

import getpass
import json

from pyksef import ksef_auth_xades
from pyksef.auth.identifier import ContextIdentifier, ContextIdentifierType, SubjectIdentifierType
from pyksef.auth.local_key import PEMPrivateKey
from pyksef.auth.state import ksef_poll_auth_finalized
from pyksef.x509 import load_pem_x509_certificate


# Certificate/key file parameters
PEM_CERT_FILENAME = "_private/ksef.crt"
PEM_KEY_FILENAME = "_private/ksef.key"
PEM_PASSPHRASE = getpass.getpass("PEM Passphrase: ")

# Authentication parameters
CONTEXT_ID = ContextIdentifier(type=ContextIdentifierType.nip, value="5421234567")
SUBJECT_ID_TYPE = SubjectIdentifierType.certificateSubject

# API URL
PROD_API_BASE_URL = "https://api.ksef.mf.gov.pl/v2"

# ---

# load X.509 certificate from file
with open(PEM_CERT_FILENAME, 'rb') as f:
    cert = load_pem_x509_certificate(f.read())

# load X.509 key from file
with open(PEM_KEY_FILENAME, 'rb') as f:
    key_pem = f.read()

# construct PEMPrivateKey object with file contents and passphrase to decrypt the key
key = PEMPrivateKey(key_pem, PEM_PASSPHRASE.encode("utf-8"))

# perform KSeF authentication with PEM certificate/key file
auth_res = ksef_auth_xades(
    api_base_url=PROD_API_BASE_URL,
    cert=cert,
    key=key,
    context_id=CONTEXT_ID,
    subject_id_type=SUBJECT_ID_TYPE,
)

# poll authentication state and redeem the actual token
# we may need to wait a little bit before the authentication is approved
auth_state = ksef_poll_auth_finalized(
    api_base_url=PROD_API_BASE_URL,
    reference_number=auth_res["referenceNumber"],
    authentication_token=auth_res["authenticationToken"]["token"]
)

print(json.dumps({
    "ksefAuthInitResult": auth_res,
    "ksefPollAuthFinalizedResult": auth_state,
}, indent=4))

Example output

All snippets in this section output their results in the same format.

{
    "ksefAuthInitResult": {
        "referenceNumber": "XXXXXXXX-XX-XXXXXXXXXX-XXXXXXXXXX-XX",
        "authenticationToken": {
            "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "validUntil": "2026-02-09T16:08:59.2602376+00:00"
        }
    },
    "ksefPollAuthFinalizedResult": {
        "redeemResult": {
            "accessToken": {
                "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
                "validUntil": "2026-02-09T15:38:58.1201962+00:00"
            },
            "refreshToken": {
                "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
                "validUntil": "2026-02-16T15:23:58.1201962+00:00"
            }
        },
        "authState": {
            "startDate": "2026-02-09T15:23:58.1401992+00:00",
            "authenticationMethod": "QualifiedSignature",
            "status": {
                "code": 200,
                "description": "Uwierzytelnianie zako\u0144czone sukcesem"
            },
            "isTokenRedeemed": false
        }
    }
}

CLI Usage

List available PKCS#11 tokens

Command:

p11_list_tokens \
    --pkcs11-dll "C:\Program Files\Krajowa Izba Rozliczeniowa S.A\Szafir 2.0\bin\CCGraphiteP11p.x64.dll"

Example output:

TokenRecord(slot=<Slot (slotID=2 flags=7)>, label='PKI Token 1 (Primary)', serial='31333132303030313233343536373839', manufacturer_id='CryptoTech P.S.A.', model='CCGraphitePro', hardware_version=(0, 0), firmware_version=(0, 0), flags=<TokenFlag.LOGIN_REQUIRED|USER_PIN_INITIALIZED|TOKEN_INITIALIZED: 1036>)
TokenRecord(slot=<Slot (slotID=3 flags=7)>, label='PKI Token 2 (QSCD)', serial='31333132303030313233343536373839', manufacturer_id='CryptoTech P.S.A.', model='CCGraphitePro', hardware_version=(0, 0), firmware_version=(0, 0), flags=<TokenFlag.WRITE_PROTECTED|LOGIN_REQUIRED|USER_PIN_INITIALIZED|TOKEN_INITIALIZED: 1038>)

List available private keys/certificates for PKCS#11 token

Command:

p11_list_objects \
    --pkcs11-dll "C:\Program Files\Krajowa Izba Rozliczeniowa S.A\Szafir 2.0\bin\CCGraphiteP11p.x64.dll" \
    --token-label "PKI Token 2 (QSCD)" \
    --token-serial "31333132303030313233343536373839"

Example output:

CertificateRecord(x509_cert=<Certificate(subject=<Name(C=PL,2.5.4.5=PNOPL-12345678900,CN=Jan Kowalski,2.5.4.42=Jan,2.5.4.4=Kowalski)>, ...)>)
PrivateKeyRecord(label='No Friendly Name Available', id='6572df736d642974a2bab6ddba753aefb89afcce', key_type=<KeyType.RSA>)

Fetch certificates stored on a PKCS#11 token

Command:

p11_list_objects \
    --pkcs11-dll "C:\Program Files\Krajowa Izba Rozliczeniowa S.A\Szafir 2.0\bin\CCGraphiteP11p.x64.dll" \
    --token-label "PKI Token 2 (QSCD)" \
    --token-serial "31333132303030313233343536373839" \
    --output certificates

Example output:

-----BEGIN CERTIFICATE-----
MIIHe...
-----END CERTIFICATE-----

Perform KSeF authentication using private key available through PKCS#11

Command:

ksef_auth_pkcs11 \
    --pkcs11-dll "C:\Program Files\Krajowa Izba Rozliczeniowa S.A\Szafir 2.0\bin\CCGraphiteP11p.x64.dll" \
    --token-label "PKI Token 2 (QSCD)" \
    --key-id 6572df736d642974a2bab6ddba753aefb89afcce \
    --context-id-type nip \
    --context-id 5421234567

Perform KSeF authentication using certificate/private key file pair stored on disk

Command:

ksef_auth_file \
    --cert-file ksef.crt \
    --key-file ksf.key \
    --context-id-type nip \
    --context-id 5421234567

Troubleshooting

In case if you see the following exception even though the DLL physically exists at the path indicated:

pkcs11.exceptions.PKCS11Error: OS exception while loading <file path>.dll: The specified module could not be found.

Please check if your PATH environment variable is set correctly. The error is actually due to the fact that your PKCS#11 DLL tries to load other DLLs that couldn't be located within the PATH.

If your PKCS#11 library comes with other required DLL files that are all hosted within the same directory, it is going to help when you add the directory of your PKCS#11 library to PATH environment variable.

Metadata

Release files for pyksef 0.3.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyksef 0.3.3
File Size Uploaded
pyksef-0.3.3.tar.gz 16.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyksef 0.3.3
File Interpreter ABI Platform
pyksef-0.3.3-py3-none-any.whl Python 3 none any Details

Total release size: 35.5 kB

Release files / pyksef-0.3.3.tar.gz

Download URL pyksef-0.3.3.tar.gz
Size 16.3 kB
Tags Source
SHA-256 checksum
How to use checksums
84e95e132a3296a8b796a31da053b6af620c94b77f423b3d767c6ee57f8d0e96
BLAKE2b-256 checksum
How to use checksums
bb34ea79c227e03f7da03c8229340de55d4a642557642e68c2dc381154007df4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 9, 2026.

Transparency log

Release files / pyksef-0.3.3-py3-none-any.whl

Download URL pyksef-0.3.3-py3-none-any.whl
Size 19.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
54d9d09abf150a07ec7a6f27938f038d1d800412351fd8241f301141aebbea65
BLAKE2b-256 checksum
How to use checksums
4b4dadc854921938535bd70328abb313efe6bd04eaf59fbadcd25c9e59cf7db2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 9, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.3 This release

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page