Životni ciklus Open API tokena
cTrader Open API dozvoljava jednu validnu access token po cTrader ID-u (cID) u jednom trenutku. U trenutku kada se izda novi token — planirano osvežavanje, ili re-authorization kada korisnik linkuje drugi račun na isti cID — prethodni access token se invalidira. Copy engine koji radi na remote node-u drži taj sada-mrtvi token, tako da novi token mora do njega bez prekidanja live konekcije.
Model
OpenApiAuthorizationje agregat koji drži cID-ov encrypted access + refresh tokene. Jedinstveni indeks na(UserId, CtidUserId)enforce-uje tačno jednu autorizaciju po cID-u po korisniku.TokenVersion— monotonic counter koji se bump-uje svaki put kada se token rotira (Refresh(), što takođe pokriva re-auth put kada je drugi račun linkovan na isti cID). To je version marker za single-valid-token pravilo i ono što running host koristi da detektuje promenu čak i ako dva token string-a slučajno koliziraju.- Tokeni su enkriptovani at rest preko
ISecretProtector(EncryptionPurposes.OpenApiAccessToken/OpenApiRefreshToken). Nikad se ne loguju niti čuvaju u plaintext-u.
Propagacija (graceful in-place swap)
- Token se rotira → novi token + bumped
TokenVersionse perzistiraju. CopyEngineSupervisorna hosting node-u ponovo čita plan svaki reconcile cycle i računa token signature (access tokeni + verzije). Promena znači rotaciju.- Umesto da se host sruši i restartuje (što bi prekinulo master's execution stream), supervisor gura novi token u running host.
- Host se re-authenticates na pogođenom računu na postojećem socket-u
(
ProtoOAAccountAuthReqponovo) prekoSwapAccessTokenAsync, zatim radi light reconcile. Stari token umire; copy stream se nikad ne zaustavlja.
Ovo čini cross-cID slučaj bezbednim: korisnik koji dodaje drugi račun sa istog cID-a usred run-a invalidira stari token, i running copy profile nastavlja na novom.
Osvežavanje
OpenApiTokenRefreshService (background) proaktivno osvežava autorizacije pre isteka;
OpenApiAuthorization.IsExpiring(threshold, now) gating-uje ga. cTrader rotira refresh token
pri svakom osvežavanju, tako da se novi refresh token perzistira odmah; read-only cache koji ne može
perzistirati bi se sam invalidirao (relevantno za in-cluster test Job, koji montira writeable copy
secret-a).
Failure escalation
Neuspešno osvežavanje nije tiho. OpenApiAuthorization.MarkRefreshFailed(reason, now, criticalWindow)
beleži RefreshFailedAt, inkrementira ConsecutiveRefreshFailures, i uvek podiže
AccessTokenRefreshFailed (warning). Kada je token sada unutar App:OpenApi:TokenRefreshCriticalWindow
(podrazumevano 6h) od isteka i osvežavanje i dalje ne uspeva, eskalira jednom sa
AccessTokenRefreshCritical domen događajem + Critical log tako da owner može re-authorize pre nego što
copy/prop-firm operacije izgube token. Failure counter i escalation latch se resetuju na sledeći
uspešni Refresh. Servis nastavlja da retrie-uje svaki TokenRefreshInterval, tako da provider/maintenance
outage self-heal-uje kada refresh endpoint vrati.
Invalidacijski alert i auto-recovery (M1)
Delimična/again-authorization na cID invalidira token koji running copy host još drži. Kada trading poziv
reject-uje sa OpenApiErrorKind.TokenInvalid, host podiže distinkt
CopyTokenInvalidated alert (log 1078) — ne generički neuspeh — tako da notifikacioni kanal zna da
token treba pažnju. Recovery je automatski: supervisor ponovo čita autorizaciju svaki cycle i,
kada osveženi token promeni token signature, gura ga u running host za in-place
swap — kopiranje se nastavlja bez manuelnog re-add-a. NotLinkable profil (token/auth privremeno
ne-resolvable) se takođe re-evaluira svaki supervisor cycle i hostuje u trenutku kada se njegov plan ponovo izgradi.
Host liveness watchdog (M2)
Supervisor gleda svaki hosted profilov run task. Ako host izađe ili fault-uje dok je njen profil još
dodeljen ovom node-u, watchdog otkazuje i restartuje ga sledeći cycle (log
CopyHostRestarted), tako da zaglajeni host self-heal-uje umesto da zahteva manuelni restart — i jedan profilov
neuspeh nikad ne blokira druge (per-profile izolacija).
Testovi
- Unit —
TokenVersionbump-uje naRefresh; host izvršava in-place swap bez restarta; cross-cID invalidacija swapa source i destination tokene; invalidiran destination token podižeCopyTokenInvalidatedi auto-recover-uje se na sledeći token push (M1); watchdogIsHostDeadodluka restartuje završeni/faulted host i ostavlja reassigned profil sam (M2). - Integration —
TokenVersionperzistira + inkrementira kroz EF na realnom Postgres-u; token signature se menja na version bump čak i ako je string nepromenjen.