I think it would be great if the library handled connection timeouts better to avoid situations like
- Mobile Safari's aggressive connection management
- Network timeouts during page lifecycle
- Background/foreground transitions
- Any transient network failures
Here's an example of what I did to fix this within my own application, so thinking something along these lines would be great to add to this library to retry in case this kind of issue happens (I'm using a library called exponential-backoff):
Inside of my app.config.ts file:
provideAppInitializer(initializeAuth),
provideAppInitializer(initializeAuthVisibilityListener),
async function initializeAuth() {
const authService = inject(AuthService);
const loggingService = inject(LoggingService);
try {
await authService.loadDiscoveryDocumentWithRetry();
} catch (error: unknown) {
loggingService.logError(error);
throw error;
}
}
function initializeAuthVisibilityListener() {
const authService = inject(AuthService);
const loggingService = inject(LoggingService);
if (typeof document === 'undefined') {
return;
}
let lastVisibleTime = Date.now();
const handleVisibilityChange = async () => {
if (document.hidden) {
lastVisibleTime = Date.now();
return;
}
const timeInBackground = Date.now() - lastVisibleTime;
if (timeInBackground > 30000) {
try {
await authService.loadDiscoveryDocumentWithRetry(true);
} catch (error: unknown) {
loggingService.logError(error);
}
}
lastVisibleTime = Date.now();
};
document.addEventListener('visibilitychange', handleVisibilityChange);
}
Inside of my Auth Service:
async loadDiscoveryDocument(shouldReloadDiscoveryDocument: boolean = false) {
if (
!this.oauthService?.discoveryDocumentLoaded ||
shouldReloadDiscoveryDocument
) {
await this.oauthService.configure(authCodeFlowConfig);
await this.oauthService.loadDiscoveryDocument();
}
}
async loadDiscoveryDocumentWithRetry(
shouldReloadDiscoveryDocument: boolean = false
): Promise<void> {
const maxRetries = 5;
return await backOff(
() => this.loadDiscoveryDocument(shouldReloadDiscoveryDocument),
{
numOfAttempts: maxRetries,
startingDelay: 1000,
timeMultiple: 2,
maxDelay: 30000,
jitter: 'full',
retry: (error: unknown) =>
this.shouldRetryLoadingDiscoveryDocument(error)
}
);
}
async loadDiscoveryDocumentAndTryLoginWithRetry() {
const maxRetries = 5;
return await backOff(
() => this.oauthService.loadDiscoveryDocumentAndTryLogin(),
{
numOfAttempts: maxRetries,
startingDelay: 1000,
timeMultiple: 2,
maxDelay: 30000,
jitter: 'full',
retry: (error: unknown) =>
this.shouldRetryLoadingDiscoveryDocument(error)
}
);
}
shouldRetryLoadingDiscoveryDocument(error: unknown) {
const isHttpError = error instanceof HttpErrorResponse;
const isNetworkError = isHttpError && error.status === 0;
const isGenericError = error instanceof Error;
const hasHttpFailureMessage =
isGenericError && error.message.includes('Http failure response');
const shouldRetry = isNetworkError || hasHttpFailureMessage;
const params =
error && typeof error === 'object' && 'params' in error
? (error as any).params
: null;
const error_description =
params && typeof params === 'object' && 'error_description' in params
? String(params.error_description)
: '';
const lowerErrorDescription = error_description?.toLowerCase() || '';
if (lowerErrorDescription.includes('user cancelled authentication')) {
return false;
}
return shouldRetry;
}
I think it would be great if the library handled connection timeouts better to avoid situations like
Here's an example of what I did to fix this within my own application, so thinking something along these lines would be great to add to this library to retry in case this kind of issue happens (I'm using a library called exponential-backoff):
Inside of my app.config.ts file:
Inside of my Auth Service: