Skip to content

Latest commit

 

History

History
170 lines (115 loc) · 7.03 KB

File metadata and controls

170 lines (115 loc) · 7.03 KB

KSeF Certificates

Reference documentation for KSeF certificate types, generation, and usage. Based on official gov.pl documentation and hands-on testing (February 2026).


Overview

KSeF issues its own certificates for system access. These are not qualified electronic signatures (like those from Certum or SimplySign) — they are certificates generated within the KSeF system itself at ap.ksef.mf.gov.pl.

Since February 1, 2026, KSeF certificates are the primary authentication method. Token-based authentication is being phased out and will be fully removed by January 1, 2027.


Certificate Types

KSeF generates two distinct certificate types. A single certificate cannot serve both purposes — they must be generated separately.

Type 1: Authentication Type 2: Offline
Purpose Login to KSeF (interactive and batch sessions) Issue invoices in offline/emergency mode
Use case Querying and downloading invoices via API Issuing invoices when KSeF is unavailable
Portal label "Uwierzytelnienie w systemie KSeF" "Podpis linku do weryfikacji wystawcy"
Relevant for us Yes — required for invoice sync No

What We Use: Type 1 (Authentication)

Our app downloads invoices from KSeF. This requires a Type 1 certificate to authenticate API sessions. When generating a certificate in the KSeF portal, the user must select "Uwierzytelnienie w systemie KSeF".


Certificate Identity: Person vs Organization

Person Certificates (what we use today)

Certificates generated by an individual in the KSeF Taxpayer Application (ap.ksef.mf.gov.pl) are always tied to the person, identified by:

  • PESEL — for employees or individuals acting on behalf of a company
  • NIP — for sole proprietors (jednoosobowa działalność gospodarcza)

Key characteristics:

  • The certificate belongs to the person, not any specific company
  • One certificate works for all companies the person is authorized to act for
  • When used, the person's identity (name, PESEL) is visible in KSeF logs
  • Only the named individual may use the certificate — sharing is prohibited

Example from the KSeF portal certificate list:

Identyfikator podmiotu:    PESEL: xxxxxxxxxxx
Nazwa właściciela:         JAN KOWALSKI
Przeznaczenie:             Uwierzytelnienie

Organization Certificates

Issued to a legal entity (e.g., sp. z o.o., SA) using the company's NIP. Requires authentication via qualified electronic seal (pieczęć elektroniczna).

Key characteristics:

  • Tied to the company NIP, not any individual
  • Multiple certificates can be generated per company
  • The company distributes certificates to employees as needed
  • When used, only company data appears in KSeF — individual identity is hidden
  • The company is responsible for certificate lifecycle management

We do not currently use organization certificates. The portal at ap.ksef.mf.gov.pl generates person certificates. Organization certificates require a qualified electronic seal, which is a separate procurement.


Certificate Generation Flow

On ap.ksef.mf.gov.pl:

  1. Login — authenticate with trusted profile (profil zaufany), qualified e-signature, or e-ID
  2. Password — enter a password to protect the private key
  3. Private key generated — the browser generates a key pair; the private key is saved to the user's device as a named file (e.g., test-111)
  4. Choose purpose:
    • "Podpis linku do weryfikacji wystawcy" (Type 2 — offline)
    • "Uwierzytelnienie w systemie KSeF" (Type 1 — authentication)
  5. Set validity — start date configurable, valid for 2 years from that date
  6. Certificate issued — available for download

Output Files

The portal produces:

  • A private key file (.key) — saved to the device during generation
  • A certificate file (.crt / .pem) — downloadable after generation

These correspond to our .key + .crt upload mode, which converts them server-side to PKCS12 format for xmlsec1 signing.


How Authentication Works

The certificate proves the signer's identity, but it does not determine which company they act for. That is specified in the API request:

1. App sends:  getChallenge(NIP = "1234567890", Type = "onip")
                                    ↑ company NIP
2. KSeF returns: challenge string

3. App signs challenge with person's certificate (XADES/xmlsec1)
                                    ↑ proves identity (PESEL-based)

4. KSeF verifies:
   - Is the certificate valid?
   - Is the certificate holder authorized for NIP 1234567890?
   - If yes → issue tokens

The same certificate can authenticate for any company where the person has KSeF authorization. The NIP in the request determines the company context, not the certificate.

Authorization Requirements

For a person's certificate to work for a company, that person must be authorized in KSeF for that company's NIP. Authorization is managed in the KSeF portal by the company's administrator or legal representative.


Validity and Lifecycle

Property Value
Maximum validity 2 years from start date
Start date Configurable at generation time
Revocation Can be revoked in the KSeF portal
Renewal Generate a new certificate before expiry
Multiple active A person can have multiple active certificates

Implications for Our Data Model

Current Model (credential per company)

Company A (NIP: 1234567890)  →  Credential row with cert data
Company B (NIP: 0987654321)  →  Credential row with same cert data (re-uploaded)

This forces the user to upload the same certificate file for each company — redundant and confusing, since the certificate belongs to the person.

Correct Model (credential per user)

User  →  One credential row with cert data
  ├── authenticates as Company A (NIP: 1234567890)
  └── authenticates as Company B (NIP: 0987654321)

The certificate should be stored on the user, and used with whichever company NIP is selected. The NIP for the getChallenge request comes from the company, not the certificate.

What Needs to Change

  • Move certificate_data_encrypted and certificate_password_encrypted from the credential (company-scoped) to the user or a new user-certificate entity
  • Keep company-specific fields (tokens, last_sync_at, NIP) on a per-company record
  • Certificate upload becomes a user-level action, not a per-company action
  • Sync workers still authenticate per-company, but share the user's certificate

References

Resource URL
KSeF certificate overview (gov.pl) https://ksef.podatki.gov.pl/informacje-ogolne-ksef-20/certyfikaty-ksef/
Certificate types explained https://akademialtca.pl/blog/czy-certyfikat-musi-byc-przypisany-do-osoby-fizycznej
KSeF Taxpayer Application https://ap.ksef.mf.gov.pl
KSeF Test Environment https://ksef-test.mf.gov.pl
KSeF Production Environment https://ksef.mf.gov.pl