KSeF 2.0 Authentication for Developers: 2026 Guide
Implement KSeF 2.0 authentication with certificates, XAdES, access and refresh tokens, least-privilege permissions, and a safe 2027 migration plan.
Ernest Bursa
KSeF 2.0 authentication is a two-layer process: prove an identity with an XAdES signature or legacy KSeF token, then use the returned JWT access token for protected API calls. Under the rules in force on 28 August 2026, the token method ends on 31 December 2026. New production integrations should use type-1 KSeF certificates.
This guide was verified against Ministry of Finance documentation and the official KSeF API repository on 28 August 2026. The API still changes, so treat the official changelog as part of your production dependency set.
How does KSeF 2.0 authentication work?
KSeF 2.0 separates authentication from invoice sessions. You first establish who is calling and in which taxpayer context. Only after receiving an accessToken do you open an online or batch session, submit invoices, query metadata, or retrieve UPO documents.
Four credentials appear in this flow. Confusing them causes many implementation errors:
| Credential | What it proves | Typical lifetime | Where it is used |
|---|---|---|---|
| KSeF certificate or qualified certificate | The identity of the authenticating person or entity | KSeF certificate: up to two years | Signs the XAdES authentication request |
| KSeF token | A legacy secret tied to one context and an immutable permission subset | Until revoked; current law permits the method through 31 December 2026 | Starts the alternative token-based authentication flow |
authenticationToken |
One pending authentication operation | Temporary and single-purpose | Polls status and is redeemed once |
accessToken and refreshToken |
The current authenticated API session | Access: minutes via exp; refresh: up to seven days |
Authorizes API calls and refreshes access |
The official authentication guide describes the final pair as JWTs issued after a successful asynchronous operation. The access token goes in Authorization: Bearer .... It is not the same object as the older, long-lived KSeF token.
Context and identity are separate
Every login combines two questions:
- Which context will this session operate in? Usually a company identified by NIP, but KSeF also supports other context identifiers.
- Whose identity is authenticating? This may be the company, a person identified by PESEL or NIP, or an identity tied to a certificate fingerprint.
KSeF checks whether the authenticating subject has at least one active permission in the selected context. A valid certificate alone is not enough. This separation matters when an accounting provider or employee works for several companies: the same identity certificate may work across multiple contexts, while permissions differ in each one.
Which KSeF authentication method should you choose in 2026?
Use XAdES with a type-1 KSeF authentication certificate for a new production integration. Keep legacy KSeF-token support only as a migration bridge. The regulation currently in force permits that method through 31 December 2026, and current Ministry guidance says certificate authentication remains available from 1 January 2027.
The deadline needs one qualification. In June 2026, the Ministry proposed extending KSeF tokens with shorter validity and renewal controls. That is a consultation proposal, not an enacted rule as of this article’s verification date. Plan against the binding cutoff until the regulation changes.
| Decision | Type-1 KSeF certificate | Legacy KSeF token |
|---|---|---|
| New production integration | Recommended | Do not build a new dependency on it |
| Works across several authorized contexts | Yes | No, each token belongs to one context |
| Carries permissions itself | No, KSeF checks current server-side permissions | Contains a fixed subset selected at creation |
| Rotation model | Expiring certificate, valid for at most two years | Secret remains until revoked, but current law has a 2026 cutoff |
| Cryptographic login | XAdES signature | Encrypt {tokenKSeF}|{timestampMs} with the KSeF public key |
| Main operational risk | Private-key compromise or expiry | Secret leakage, scope sprawl, and forced migration |
The distinction comes directly from the Ministry of Finance KSeF 2.0 handbook: a certificate carries identity but no KSeF permissions, while a KSeF token carries a permission subset and is confined to one context.
Do not use an offline certificate for authentication
KSeF issues two certificate types with different purposes:
-
Authenticationsigns the login request. -
Offlineproves issuer authenticity and invoice integrity in an offline flow.
An Offline certificate cannot authenticate API calls. The official certificate guide also warns against using an authentication certificate to sign offline invoice evidence. Store and label the two private keys separately so deployments cannot select the wrong one.
How do you implement certificate authentication?
Certificate authentication is an asynchronous challenge-response flow. Your client signs XML locally, submits it, polls the operation, and redeems a temporary token exactly once.
1. Request a challenge
Call POST /auth/challenge, then keep both the challenge value and its timestamp. The challenge is valid for 10 minutes. It binds the next request to a fresh authentication attempt and prevents replaying an old signed document. Create a new challenge for every attempt instead of caching one.
2. Build AuthTokenRequest
Construct the XML request with:
- the challenge,
- the context identifier and value,
- the subject identifier type,
- an optional
AuthorizationPolicyrestricting allowed IPv4 addresses, ranges, or masks.
If the certificate contains the company’s NIP, the subject may authenticate directly. If a person signs for a company, KSeF resolves the person’s identifier from the certificate and checks their permissions in the company’s context. For qualified certificates without NIP or PESEL, an authorized certificate fingerprint may be required.
3. Create a compliant XAdES signature
Sign the XML with the selected identity certificate and its private key. Do not assume an old KSeF 1.0 XAdES sample is still accepted. API 2.1.0 tightened XAdES validation, and the current rules already apply across the live environments according to the KSeF API changelog. The current XAdES requirements accept enveloped and enveloping signatures but reject detached signatures; they also set minimum RSA and EC key sizes.
The Ministry maintains reference clients for C# and Java. Even when your application uses another language, their tests are useful executable examples for XML serialization, certificate identifiers, and signature construction.
4. Submit and poll
Send the signed XML to POST /auth/xades-signature. A successful submission returns:
-
referenceNumber, which identifies the asynchronous operation; -
authenticationToken, a temporary JWT used only for this operation.
Poll GET /auth/{referenceNumber} with the temporary token. Poll at a bounded interval and classify responses into three groups: still processing, terminal success, and terminal failure. Invalid signatures, certificate problems, missing permissions, and security blocking are not transient network errors. Retrying the same broken document indefinitely only hides the real failure.
5. Redeem once
When authentication succeeds, call POST /auth/token/redeem with the temporary token. KSeF returns accessToken and refreshToken. Redemption is one-shot; the authentication documentation says reusing the same authenticationToken returns HTTP 400.
A compact implementation outline looks like this:
challenge = POST /auth/challenge
request = build_auth_xml(challenge, context, subject, allowed_ips)
signed_xml = xades_sign(request, identity_certificate, private_key)
operation = POST /auth/xades-signature(signed_xml)
status = poll GET /auth/{operation.referenceNumber}
Authorization: Bearer {operation.authenticationToken}
tokens = POST /auth/token/redeem
Authorization: Bearer {operation.authenticationToken}
call protected endpoints with tokens.accessToken
refresh before accessToken.exp with tokens.refreshToken
6. Open invoice sessions separately
Authentication does not open an invoice session. Once you hold a valid access token, use it to open POST /sessions/online or POST /sessions/batch. KSeF 2.0 deliberately separates these concerns, so one authentication session can authorize more than the single session-opening operation supported by older integrations.
What if you still authenticate with a KSeF token?
The legacy branch starts with the same POST /auth/challenge, but does not sign XML. Build {tokenKSeF}|{timestampMs} from the secret and challenge timestamp, encrypt it with the current KSeF public key using RSA-OAEP with SHA-256/MGF1, and send the Base64 result to POST /auth/ksef-token with the challenge, context, and selected publicKeyId.
Fetch encryption keys from GET /security/public-key-certificates; do not pin one public key in code. The official key-rotation guide describes planned and emergency rotation. If KSeF rejects a withdrawn or unknown key identifier, refresh the key set and retry the operation with a fresh challenge.
From that point, polling and one-time redemption match the XAdES flow. The KSeF token itself must never appear in logs. It is the root secret for this branch, not the temporary authenticationToken or the returned access JWT.
How should access and refresh tokens be handled?
Treat both returned JWTs as credentials, not harmless session metadata. The access token is short-lived, but it remains usable until the exp time even if an administrator changes the subject’s permissions during that window. A newly refreshed access token receives the current roles and permissions.
Build the following controls into the client:
-
Read
exp; do not hard-code a guessed TTL. Refresh with a safety margin and jitter so workers do not all refresh at the same second. - Single-flight refresh per credential set. When several workers notice expiry, let one refresh and share the result. A refresh storm adds failure modes without adding availability.
-
Never log bearer tokens. Redact
Authorizationheaders, response bodies from token endpoints, exception payloads, and tracing attributes. - Keep refresh tokens out of browser storage. A server-side integration should hold them in an encrypted credential store with access limited to the worker that needs them.
- Handle refresh failure as reauthentication. An expired or invalid refresh token should return the client to the certificate flow, not an unbounded refresh loop.
-
Use server time carefully. Clock skew near
expcreates intermittent authorization failures, so monitor time synchronization and refresh early.
The official guide describes an access-token lifetime of several minutes and refresh-token validity of up to seven days. Those are implementation bounds, not a reason to copy a numeric constant from a blog post. The JWT and current API contract are the source of truth.
How do permissions interact with KSeF certificates?
A KSeF certificate is an identity credential, not a master key. The certificate documentation states that the certificate is not assigned to a context and contains no KSeF permissions. KSeF evaluates the subject’s permissions for the requested context on the server.
This leads to a cleaner access model:
- issue an identity certificate to the person or entity that operates the integration;
- grant only the required permissions in each taxpayer context;
- query effective permissions during setup and diagnostics;
- remove permissions when the relationship ends without unnecessarily revoking the identity certificate everywhere;
- revoke the certificate when the private key is compromised or the identity credential itself should no longer be trusted.
For a worker that only submits invoices, begin with InvoiceWrite. Add InvoiceRead only if that process actually downloads or searches invoices. Keep CredentialsManage away from routine invoice workers. The official permissions guide exposes queries for current permissions and roles, which are safer than inferring access from a successful login months earlier.
One trap deserves emphasis: the XAdES authentication request has no requestedPermissions field that turns a broadly authorized identity into a narrowly scoped certificate session. If an Owner identity authenticates, the resulting access can reflect that identity’s current rights. Least privilege therefore starts with the identity and its server-side grants, not with the certificate file. The optional IP policy narrows where a token may be used, not which operations it may perform.
Revocation is not instantaneous for every credential
There are two timing effects to design around:
- Revoking a type-1 KSeF certificate used by an active session terminates that session, according to the Ministry handbook.
- Removing a permission does not retroactively rewrite an already-issued access token. The token can remain valid until
exp; refresh obtains current permissions.
For urgent containment, revoke the compromised certificate and stop the local worker. For routine offboarding, remove permissions, invalidate stored refresh material in your system, and expect a short access-token tail. Log the subject, context, token issue time, and certificate serial number, but never the token value or private key.
What changes between TEST, DEMO, and production?
Authentication code should be identical across environments, but the trust assumptions are not.
| Environment | Endpoint | What to verify |
|---|---|---|
| TEST | https://api-test.ksef.mf.gov.pl/v2 |
Current API behavior, XAdES validation, error handling, and rotation logic |
| DEMO | https://api-demo.ksef.mf.gov.pl/v2 |
Production-like certificate chain and end-to-end configuration |
| PRD | https://api.ksef.mf.gov.pl/v2 |
Real identity, real permissions, monitored credentials, and legally effective invoices |
TEST accepts self-signed certificates. That convenience changes the data boundary: the official environments guide warns that several integrators may authenticate in the same test-company context. Use random NIPs and synthetic invoice data. Never send a real customer’s identity, address, invoice, or production credential into TEST.
Do not promote a TEST-only self-signed certificate to DEMO or production. Validate the real certificate path in DEMO, including chain validation, CSR data, secret loading, certificate expiry alerts, and a rotation period in which the old and new credentials overlap.
What should you migrate before the current 2027 cutoff?
If your integration still starts with a KSeF token, complete certificate authentication before the end of 2026 under the rules currently in force. A proposed extension may change the date, but it should not change the architecture of a new integration. The safest sequence is operational, not just cryptographic.
- Inventory every KSeF token, its owner, context, permissions, last use, and consuming service.
- Issue type-1 KSeF certificates to the appropriate people or entities.
- Implement the XAdES challenge, status polling, redeem, and refresh flow in TEST.
- Run the certificate path in DEMO with production-like key storage and network policy.
- Enable certificate authentication in production behind a controlled rollout.
- Compare successful contexts and effective permissions between old and new paths.
- Move all traffic, observe at least one full rotation and failure-recovery cycle, then revoke old KSeF tokens.
Do not wait until December to discover that the process depends on a qualified seal held by one person, the CSR identity data does not match, or your HSM cannot produce the required XAdES signature. Certificate enrollment is asynchronous, certificates expire, and operational ownership takes longer to fix than endpoint code.
How Kit approaches KSeF authentication
Kit’s KSeF for Stripe integration turns finalized Stripe invoices into FA(3), submits them to KSeF, and keeps the resulting evidence in the billing workflow. That experience reinforces the architecture in this guide: identity credentials, taxpayer context, permissions, short-lived API access, invoice sessions, and UPO retrieval are separate states and should stay separate in code.
The practical standard is simple. Use certificates for identity, permissions for authorization, JWTs for bounded API access, and explicit records for every asynchronous operation. Follow Kit’s broader security approach, monitor the KSeF changelog, test rotation before expiry, and make the current 2027 token cutoff a migration milestone rather than a New Year’s incident.
Running Stripe billing for a Polish company? See how KSeF for Stripe handles FA(3) submission and UPO retrieval, explore Kit’s wider product documentation, or start a free trial.
Related articles
Ready to hire smarter?
Start free for 30 days. Cancel before it ends and you pay nothing. Set up your first hiring pipeline in minutes.
Start hiring free