Cześć,
Poratuje ktoś pomocą - integruję własny system FK z KSeF 2.0 i testuję pełny proces autoryzacji tokenem KSeF w środowisku DEMO.
Mam wdrożony kompletny przepływ:
/api/v2/auth/challenge
szyfrowanie tokenu RSA-OAEP SHA256
/api/v2/auth/ksef-token
polling /api/v2/auth/status/{referenceNumber}
/api/v2/auth/token
wysyłka FA(3) – InitUpload → Upload → Finish
Krok 1 i 2 działają prawidłowo.
Problem pojawia się od kroku 4 – /auth/status, który w DEMO nie zwraca żadnych danych (HTTP 204 No Content).
W efekcie /auth/token również zwraca pustą odpowiedź, więc nie jesteśmy w stanie pobrać accessToken – co blokuje dalszą wysyłkę faktur FA(3).
Mój kod...…..….....
using System;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
class Program
{
// ================================================
// KONFIGURACJA
// ================================================
static string NIP = "moj_NIP";
static string TOKEN = "moj_token";
static string XML_FILE = @"C:\KSeF\24150_.xml";
static string PEM_FILE = @"C:\KSeF\publicKey.pem";
static string LOG_DIR = @"C:\KSeF\Logs";
static async Task Main()
{
Directory.CreateDirectory(LOG_DIR);
using var http = new HttpClient();
Console.WriteLine("=== AUTORYZACJA KSeF 2.0 DEMO START ===");
// ================================================
// 1) CHALLENGE
// ================================================
var challengeReq = new { contextIdentifier = new { type = "onip", value = NIP } };
var challengeResp = await http.PostAsync(
"https://ksef-demo.mf.gov.pl/api/v2/auth/challenge",
new StringContent(JsonSerializer.Serialize(challengeReq), Encoding.UTF8, "application/json")
);
var challengeJson = await challengeResp.Content.ReadAsStringAsync();
File.WriteAllText(Path.Combine(LOG_DIR, "1_challenge.json"), challengeJson);
Console.WriteLine("CHALLENGE:\n" + challengeJson);
using var doc1 = JsonDocument.Parse(challengeJson);
string challenge = doc1.RootElement.GetProperty("challenge").GetString();
string timestamp = doc1.RootElement.GetProperty("timestamp").GetString();
long timestampMs = DateTimeOffset.Parse(timestamp).ToUnixTimeMilliseconds();
// ================================================
// 2) SZYFROWANIE TOKENA
// ================================================
string toEncrypt = $"{TOKEN}|{timestampMs}";
byte[] tokenBytes = Encoding.UTF8.GetBytes(toEncrypt);
string pem = File.ReadAllText(PEM_FILE)
.Replace("-----BEGIN PUBLIC KEY-----", "")
.Replace("-----END PUBLIC KEY-----", "")
.Replace("\n", "")
.Replace("\r", "");
byte[] keyBytes = Convert.FromBase64String(pem);
using RSA rsa = RSA.Create();
rsa.ImportSubjectPublicKeyInfo(keyBytes, out _);
string encryptedToken = Convert.ToBase64String(
rsa.Encrypt(tokenBytes, RSAEncryptionPadding.OaepSHA256)
);
// ================================================
// 3) /auth/ksef-token
// ================================================
var authReq = new
{
challenge = challenge,
contextIdentifier = new { type = "nip", value = NIP },
encryptedToken = encryptedToken
};
var authResp = await http.PostAsync(
"https://ksef-demo.mf.gov.pl/api/v2/auth/ksef-token",
new StringContent(JsonSerializer.Serialize(authReq), Encoding.UTF8, "application/json")
);
var authJson = await authResp.Content.ReadAsStringAsync();
File.WriteAllText(Path.Combine(LOG_DIR, "2_auth_ksef-token.json"), authJson);
Console.WriteLine("\nAUTH/KSEF-TOKEN:\n" + authJson);
using var doc2 = JsonDocument.Parse(authJson);
var authTokenObj = doc2.RootElement.GetProperty("authenticationToken");
string authToken = authTokenObj.GetProperty("token").GetString();
string validUntil = authTokenObj.GetProperty("validUntil").GetString();
string refNum = doc2.RootElement.GetProperty("referenceNumber").GetString();
Console.WriteLine($"AuthToken: {authToken}\nWażny do: {validUntil}\nRefNum: {refNum}");
// ================================================
// 4) POLLING /auth/status/{refNum}
// ================================================
string statusUrl = $"https://ksef-demo.mf.gov.pl/api/v2/auth/status/{refNum}";
string statusJson = "";
for (int i = 0; i < 10; i++)
{
Console.WriteLine($"Czekam na status ({i + 1}/10)...");
await Task.Delay(2000);
var statusResp = await http.GetAsync(statusUrl);
statusJson = await statusResp.Content.ReadAsStringAsync();
if (!string.IsNullOrWhiteSpace(statusJson) && statusJson.Contains("ready"))
break;
}
File.WriteAllText(Path.Combine(LOG_DIR, "3_auth_status.json"), statusJson);
Console.WriteLine("\nSTATUS:\n" + statusJson);
// ================================================
// 5) POBRANIE accessToken
// ================================================
var tokenReq = new { authenticationToken = authToken };
var tokenResp = await http.PostAsync(
"https://ksef-demo.mf.gov.pl/api/v2/auth/token",
new StringContent(JsonSerializer.Serialize(tokenReq), Encoding.UTF8, "application/json")
);
var tokenJson = await tokenResp.Content.ReadAsStringAsync();
File.WriteAllText(Path.Combine(LOG_DIR, "4_accessToken.json"), tokenJson);
Console.WriteLine("\nTOKEN:\n" + tokenJson);
using var doc3 = JsonDocument.Parse(tokenJson);
string accessToken = doc3.RootElement.GetProperty("token").GetString();
Console.WriteLine("\nAccessToken: " + accessToken);
// ================================================
// 6) InitUpload – FA(3)
// ================================================
string xmlContent = File.ReadAllText(XML_FILE);
string xmlHash = Convert.ToBase64String(SHA256.HashData(Encoding.UTF8.GetBytes(xmlContent)));
var initReq = new
{
contextIdentifier = new { type = "nip", value = NIP },
invoiceType = "FA3",
invoiceHash = xmlHash,
inputHashType = "SHA-256"
};
var initResp = await http.PostAsync(
"https://ksef-demo.mf.gov.pl/api/v2/online/Session/InitUpload",
new StringContent(JsonSerializer.Serialize(initReq), Encoding.UTF8, "application/json")
{
Headers = { { "Authorization", $"Bearer {accessToken}" } }
}
);
string initJson = await initResp.Content.ReadAsStringAsync();
File.WriteAllText(Path.Combine(LOG_DIR, "5_initUpload.json"), initJson);
Console.WriteLine("\n=== InitUpload Zakończony ===");
Console.WriteLine(initJson);
}
}
Czy w środowisku DEMO (uruchomione 15 listopada 2025) endpointy:
GET /api/v2/auth/status/{referenceNumber}
POST /api/v2/auth/token
są już aktywne, czy ich obsługa zostanie dopiero uruchomiona w kolejnych dniach?
Dokumentacja opisuje pełny proces, ale faktycznie:
/auth/challenge działa
/auth/ksef-token działa
/auth/status zwraca 204 No Content
/auth/token również zwraca pustą odpowiedź
Czy to znany problem?
Czy MF potwierdziło gdzieś ETA aktywacji tego fragmentu autoryzacji?
Każda wskazówka mile widziana.