Skip to content

Commit fac285e

Browse files
elinohlssonElin Fokine
andauthored
Changed retry logic for http calls in typescript code. (#528)
* Changed retry logic for http calls in typescript code, so that: 1. Duplicate retires is not fired for the same failed request. 2. Calls to checkstatus is not retried if status failed is returned from the BankID API, since the retry will just result in another error in that case. * Updates our CI configuration to handle recent macOS runner changes: 1. Removed macOS jobs from Azure DevOps because Microsoft no longer provides x86-compatible macOS agents. 2. Updated GitHub Actions to use macos-15-intel to ensure continued support for x86 builds on GitHub, since the default macos-latest runner is now ARM-based. --------- Co-authored-by: Elin Fokine <ElinO@activesolution.se>
1 parent 1ca46e4 commit fac285e

4 files changed

Lines changed: 43 additions & 27 deletions

File tree

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
include:
2020
- os: windows-latest
2121
artifactName: activelogin-authentication-nuget-windows
22-
- os: macos-latest
22+
- os: macos-15-intel
2323
artifactName: activelogin-authentication-nuget-macos
2424
- os: ubuntu-latest
2525
artifactName: activelogin-authentication-nuget-ubuntu
@@ -87,7 +87,7 @@ jobs:
8787
include:
8888
- os: windows-latest
8989
artifactName: activelogin-authentication-samples-windows
90-
- os: macos-latest
90+
- os: macos-15-intel
9191
artifactName: activelogin-authentication-samples-macos
9292
- os: ubuntu-latest
9393
artifactName: activelogin-authentication-samples-ubuntu

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
matrix:
2020
include:
2121
- os: windows-latest
22-
- os: macos-latest
22+
- os: macos-15-intel
2323
- os: ubuntu-latest
2424

2525
steps:

azure-pipelines.yml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ stages:
2121
Windows:
2222
vmImage: 'windows-latest'
2323
artifactName: 'nuget-windows'
24-
macOS:
25-
vmImage: 'macOS-latest'
26-
artifactName: 'nuget-macos'
2724
Linux:
2825
vmImage: 'ubuntu-latest'
2926
artifactName: 'nuget-linux'
@@ -99,9 +96,6 @@ stages:
9996
Windows:
10097
vmImage: 'windows-latest'
10198
artifactName: 'samples-windows'
102-
macOS:
103-
vmImage: 'macOS-latest'
104-
artifactName: 'samples-macos'
10599
Linux:
106100
vmImage: 'ubuntu-latest'
107101
artifactName: 'samples-linux'

src/ActiveLogin.Authentication.BankId.AspNetCore/Client/activelogin-main.ts

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ function activeloginInit(configuration: IBankIdUiScriptConfiguration, initState:
2323
const fetchRetryCountDefault: number = 3;
2424
const fetchRetryDelayMs: number = 1000;
2525

26+
const retryOnHttpErrors = {
27+
initialize: true,
28+
status: false, // A second call to the BankID collect endpoint is not supported after a status complete or failed is returned.
29+
qr: true,
30+
cancel: true
31+
};
32+
2633
// Pre check
2734

2835
const requiredFeatures = [window.fetch, window.sessionStorage];
@@ -123,7 +130,7 @@ function activeloginInit(configuration: IBankIdUiScriptConfiguration, initState:
123130
requestVerificationToken,
124131
{
125132
"returnUrl": returnUrl
126-
}, fetchRetryCountDefault)
133+
}, fetchRetryCountDefault, retryOnHttpErrors.initialize)
127134
.then(data => {
128135
if (data.isAutoLaunch) {
129136
if (!data.checkStatus) {
@@ -177,7 +184,9 @@ function activeloginInit(configuration: IBankIdUiScriptConfiguration, initState:
177184
"orderRef": orderRef,
178185
"returnUrl": returnUrl,
179186
"autoStartAttempts": autoStartAttempts
180-
}, fetchRetryCountDefault)
187+
},
188+
fetchRetryCountDefault,
189+
retryOnHttpErrors.status)
181190
.then(data => {
182191
if (data.retryLogin) {
183192
autoStartAttempts++;
@@ -227,7 +236,7 @@ function activeloginInit(configuration: IBankIdUiScriptConfiguration, initState:
227236
requestVerificationToken,
228237
{
229238
"qrStartState": qrStartState
230-
}, fetchRetryCountDefault)
239+
}, fetchRetryCountDefault, retryOnHttpErrors.qr)
231240
.then(data => {
232241
if (!!data.qrCodeAsBase64) {
233242
qrLastRefreshTimestamp = new Date();
@@ -278,7 +287,13 @@ function activeloginInit(configuration: IBankIdUiScriptConfiguration, initState:
278287

279288
// Helpers
280289

281-
function postJson(url: string, requestVerificationToken: string, data: any, retryCount: number = 0): Promise<any> {
290+
function postJson(url: string, requestVerificationToken: string, data: any, remaingRetryCount: number = 0, retryOnHttpError: boolean = true): Promise<any> {
291+
292+
const retry = () => {
293+
return delay(fetchRetryDelayMs)
294+
.then(() => postJson(url, requestVerificationToken, data, remaingRetryCount - 1, retryOnHttpError));
295+
};
296+
282297
return fetch(url,
283298
{
284299
method: "POST",
@@ -290,22 +305,10 @@ function activeloginInit(configuration: IBankIdUiScriptConfiguration, initState:
290305
credentials: 'include',
291306
body: JSON.stringify(data)
292307
})
293-
.catch(error => {
294-
if (retryCount > 0) {
295-
return delay(fetchRetryDelayMs).then(() => {
296-
return postJson(url, requestVerificationToken, data, retryCount - 1);
297-
});
298-
}
299-
300-
throw error;
301-
})
302308
.then(response => {
303-
if (!response.ok && retryCount > 0) {
304-
return delay(fetchRetryDelayMs).then(() => {
305-
return postJson(url, requestVerificationToken, data, retryCount - 1)
306-
});
309+
if (!response.ok && retryOnHttpError && remaingRetryCount > 0) {
310+
return retry();
307311
}
308-
309312
return response;
310313
})
311314
.then(response => {
@@ -321,6 +324,25 @@ function activeloginInit(configuration: IBankIdUiScriptConfiguration, initState:
321324
throw Error(data.errorMessage);
322325
}
323326
return data;
327+
})
328+
.catch(error => {
329+
// A TypeError here means fetch failed before receiving any HTTP response
330+
// (network down, DNS error, CORS block, connection aborted, etc.).
331+
// These failures are transient and safe to retry.
332+
const isNetworkError = error instanceof TypeError;
333+
334+
// Other error types should NOT be retried here:
335+
// - HTTP-level failures (e.g., non-2xx status codes) are already handled in the
336+
// previous `.then` block, where retry behavior is controlled by `retryOnHttpError`.
337+
// - Any error thrown after that stage represents a *valid server response*,
338+
// meaning the request reached the API and should not be repeated.
339+
// Retrying such cases here could cause duplicated API calls or break BankID flows
340+
// (e.g.collect/status), which do not allow repeated calls after a completed/failed state.
341+
if (isNetworkError && remaingRetryCount > 0) {
342+
return retry();
343+
}
344+
345+
throw error;
324346
});
325347
}
326348

0 commit comments

Comments
 (0)