Repository navigation
Commit 4911dc1
authored
improvement(credentials): keep valid client-credential tokens through refresh outages and pace token retries by failure kind (#9925)
* feat(credentials): carry a provider's Retry-After on token request failures
A 429 or 503 token answer now records its Retry-After (delay-seconds or
HTTP-date, RFC 9110 section 10.2.3) as an optional retryAfterMs on
TokenServiceAccountValidationError, through throwForProviderResponse and the
shared client-credentials grant, whose provider classifier receives it.
* feat(credentials): keep valid client-credential tokens through refresh outages
The per-instance client-credential mint cache now:
- serves a cached token that is inside its five-minute early-refresh window
but not expired when the refresh fails with an outage or throttling, as
MSAL, Azure.Core and botocore do; a refusal of the credentials still fails
- retries a quick transient mint failure once after about a second
- replays failures by kind instead of a flat 30 s: a refusal 30 s, a
throttled answer for its Retry-After (1 s to 5 min), an outage 5 s growing
to 30 s while it continues
The policy lives in lib/credentials/token-request-resilience.ts so the
coordinated resolver can share it.
* feat(credentials): share token refresh resilience across workers in the coordinated resolver
The coordinated client-credentials resolver (Shopify, Linear, Atlassian,
Vanta) now applies the same policy as the per-instance mint cache, through
the shared row every worker reads:
- a quick outage is retried once under the application lock, within the 15 s
its waiters allow
- a refusal is remembered 30 s, a throttled answer for its Retry-After (1 s to
5 min, Vanta's now included), an outage 5 s growing to 30 s while it lasts
- while an outage or throttling is remembered, the stored token for the same
secret is served until 30 s before it expires; a refusal fails at once
Rolling deploys stay safe: a refusal is stored exactly as before, and outages
add only a consecutiveFailures key that previous decoders ignore (both prior
decoders are pinned in the integration tests). The replay length rides on the
row's existing expiresAt. Expired memos are kept five more minutes so the next
failure can extend the backoff; an older build's sweep only resets it.
* fix(credentials): pace throttled and Vanta token retries and replay remembered failures without the lock
- A 429 that names no Retry-After is replayed for at least a minute, doubling
up to the five-minute cap, instead of the 5 s outage curve.
- The outage backoff never undercuts Entra's 5 s first-retry floor through jitter.
- Vanta asks for a token at most once per 15 s while exchanges fail (no
in-request retry, replay floored), within its documented 5 tokens a minute,
through a new optional minExchangeIntervalMs on the coordinated resolver.
- A remembered failure and the still-valid fallback are served from committed
rows before the application lock is taken, so a refresh outage no longer
serializes every resolution behind the lock.
- retryAfterMs now only carries a provider's Retry-After; a replayed memo
reports its remainder as the additive replayForMs, which the per-instance
layer honors exactly.
- One decode/verify path for stored tokens; the stored-failure permanence
check uses isPermanentTokenFailureCode instead of building an error.
* fix(credentials): honor every minter's Retry-After and close token fallback gaps
- Carry the token endpoint's Retry-After on 429/503 failures from every
bespoke client-credential minter (Box, Zoom, DocuSign, NetSuite, Help
Scout, Ramp, Jama, Zendesk, Salesforce, Zoho Desk) and through the
CrowdStrike, SailPoint and ZoomInfo client errors, so their throttled
answers wait as long as the provider asks instead of the fixed backoff.
- Recheck the 30 s expiry margin when the per-instance cache falls back
to a still-valid token after a slow failed refresh.
- Map an unreadable Vanta token body to provider_unavailable so it is
remembered for every worker and paced at 15 s like any failed exchange.
- Remember a refusal whose code the shared failure row cannot store with
an additive `refusal` flag, so a replay never serves the stale token.
- Rename the credentials helper to throttledRetryAfterMs so it no longer
shares a name with providers/retry.ts.
* fix(credentials): keep throttling and outage backoff streaks apart and redact the fallback log in selector mode
* fix(credentials): end a refused token, read legacy refusals as refusals, and keep throttle delays through SailPoint and CrowdStrike
- A refusal of the credentials drops the per-instance cached token and expires the shared
token minted with that secret, so a later outage cannot serve it again.
- A previous build's provider_unavailable memo with a non-transient 4xx status replays as a
refusal instead of serving the stored token.
- The SailPoint saved-credential minter returns the first 429 with its Retry-After instead of
retrying until the exchange timeout swallows it.
- A CrowdStrike error whose body cannot be read keeps its status and Retry-After.
- Vanta logs a malformed or oversized token response apart from an unreadable stream.
* fix(credentials): keep SailPoint throttle delays through unreadable error bodies and replay only coordinated failures locally
- A SailPoint token error whose body cannot be read keeps its status and Retry-After,
as CrowdStrike's does; caller cancellation still propagates.
- A shared-token (Vanta) mint failure is replayed per instance only when the coordinated
layer remembers it (replayForMs); a failure it does not remember asks again at once.
* fix(credentials): skip the fallback token once a provider refused it during the failed refresh1 parent bcadf23 commit 4911dc1
41 files changed
Lines changed: 1856 additions & 233 deletions
File tree
- apps/sim/lib
- credentials
- client-credential-accounts
- minters
- token-service-accounts
- grants
- internal
- crowdstrike
- sailpoint
- zoominfo
- oauth
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
102 | | - | |
103 | | - | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
104 | 109 | | |
105 | 110 | | |
106 | 111 | | |
107 | 112 | | |
| 113 | + | |
108 | 114 | | |
109 | 115 | | |
110 | 116 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
176 | 177 | | |
177 | 178 | | |
178 | 179 | | |
179 | | - | |
180 | | - | |
181 | | - | |
182 | | - | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
183 | 186 | | |
184 | 187 | | |
185 | 188 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
87 | 120 | | |
88 | 121 | | |
89 | 122 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
| 85 | + | |
| 86 | + | |
86 | 87 | | |
87 | 88 | | |
88 | 89 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
254 | 254 | | |
255 | 255 | | |
256 | 256 | | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
257 | 268 | | |
258 | 269 | | |
259 | 270 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| |||
266 | 267 | | |
267 | 268 | | |
268 | 269 | | |
269 | | - | |
270 | | - | |
271 | | - | |
272 | | - | |
273 | | - | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
274 | 276 | | |
275 | 277 | | |
276 | 278 | | |
| |||
297 | 299 | | |
298 | 300 | | |
299 | 301 | | |
300 | | - | |
301 | | - | |
302 | | - | |
303 | | - | |
304 | | - | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
305 | 308 | | |
306 | 309 | | |
307 | 310 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| |||
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
31 | | - | |
| 32 | + | |
| 33 | + | |
32 | 34 | | |
33 | 35 | | |
34 | 36 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
33 | 47 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
52 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
53 | 56 | | |
54 | 57 | | |
55 | 58 | | |
| |||
0 commit comments