From a080ebc69ea82fb397fbdb1a19c5e1b4f3290cdb Mon Sep 17 00:00:00 2001 From: Fahri Gedik Date: Fri, 25 Jul 2025 15:33:21 +0300 Subject: [PATCH 1/2] Add async auth guard support for OAuth routes Introduced asyncAuthGuard and asyncAbpOAuthGuard to enable asynchronous authentication checks, particularly for OAuth flows involving code exchange. Updated app routes and OAuth module provider to use the new async guards where appropriate. --- .../core/src/lib/abstracts/auth.guard.ts | 6 ++++ .../oauth/src/lib/guards/oauth.guard.ts | 32 ++++++++++++++++++- .../providers/oauth-module-config.provider.ts | 7 +++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/abstracts/auth.guard.ts b/npm/ng-packs/packages/core/src/lib/abstracts/auth.guard.ts index 50473e4df1..020f750555 100644 --- a/npm/ng-packs/packages/core/src/lib/abstracts/auth.guard.ts +++ b/npm/ng-packs/packages/core/src/lib/abstracts/auth.guard.ts @@ -21,3 +21,9 @@ export const authGuard: CanActivateFn = () => { console.error('You should add @abp/ng-oauth packages or create your own auth packages.'); return false; }; + + +export const asyncAuthGuard: CanActivateFn = () => { + console.error('You should add @abp/ng-oauth packages or create your own auth packages.'); + return false; +}; \ No newline at end of file diff --git a/npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts b/npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts index 6f751804cd..e7f31643aa 100644 --- a/npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts +++ b/npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts @@ -6,7 +6,7 @@ import { CanActivateFn, } from '@angular/router'; -import { Observable } from 'rxjs'; +import { Observable, interval, filter, take, map, firstValueFrom, timeout, catchError, of } from 'rxjs'; import { OAuthService } from 'angular-oauth2-oidc'; import { AuthService, IAbpGuard } from '@abp/ng.core'; @@ -53,3 +53,33 @@ export const abpOAuthGuard: CanActivateFn = ( authService.navigateToLogin(params); return false; }; + +export const asyncAbpOAuthGuard: CanActivateFn = ( + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot, +) => { + const authService = inject(AuthService); + const code = new URLSearchParams(window.location.search).get('code'); + + if (code) { + return firstValueFrom( + interval(100).pipe( + map(() => authService.isAuthenticated), + filter(isAuthenticated => isAuthenticated), + take(1), + timeout(3000), + catchError(() => { + authService.navigateToLogin({ returnUrl: state.url }); + return of(false); + }) + ) + ); + } + + if (authService.isAuthenticated) { + return true; + } + + authService.navigateToLogin({ returnUrl: state.url }); + return false; +}; diff --git a/npm/ng-packs/packages/oauth/src/lib/providers/oauth-module-config.provider.ts b/npm/ng-packs/packages/oauth/src/lib/providers/oauth-module-config.provider.ts index 92ecc86012..534882dd13 100644 --- a/npm/ng-packs/packages/oauth/src/lib/providers/oauth-module-config.provider.ts +++ b/npm/ng-packs/packages/oauth/src/lib/providers/oauth-module-config.provider.ts @@ -2,6 +2,7 @@ import { AuthService, AuthGuard, authGuard, + asyncAuthGuard, ApiInterceptor, PIPE_TO_LOGIN_FN_KEY, CHECK_AUTHENTICATION_STATE_FN_KEY, @@ -11,7 +12,7 @@ import { import { Provider, makeEnvironmentProviders, inject, provideAppInitializer } from '@angular/core'; import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { OAuthModule, OAuthStorage } from 'angular-oauth2-oidc'; -import { AbpOAuthGuard, abpOAuthGuard } from '../guards'; +import { AbpOAuthGuard, abpOAuthGuard, asyncAbpOAuthGuard, } from '../guards'; import { OAuthConfigurationHandler } from '../handlers'; import { OAuthApiInterceptor } from '../interceptors'; import { AbpOAuthService, OAuthErrorFilterService } from '../services'; @@ -31,6 +32,10 @@ export function provideAbpOAuth() { { provide: authGuard, useValue: abpOAuthGuard, + }, + { + provide: asyncAuthGuard, + useValue: asyncAbpOAuthGuard, }, { provide: ApiInterceptor, From f5d1731793d0f15828ebefb383130a1cd90a9a88 Mon Sep 17 00:00:00 2001 From: Fahri Gedik Date: Wed, 30 Jul 2025 12:06:26 +0300 Subject: [PATCH 2/2] Refactor OAuth guard to use OAuthService and timer Replaces usage of AuthService.isAuthenticated and interval with OAuthService.hasValidAccessToken() and timer for checking authentication status. Also injects EnvironmentService to access OAuth configuration and updates logic to check responseType before waiting for authentication. --- .../oauth/src/lib/guards/oauth.guard.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts b/npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts index e7f31643aa..1311a8d7a8 100644 --- a/npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts +++ b/npm/ng-packs/packages/oauth/src/lib/guards/oauth.guard.ts @@ -6,10 +6,10 @@ import { CanActivateFn, } from '@angular/router'; -import { Observable, interval, filter, take, map, firstValueFrom, timeout, catchError, of } from 'rxjs'; +import { Observable, timer, filter, take, map, firstValueFrom, timeout, catchError, of } from 'rxjs'; import { OAuthService } from 'angular-oauth2-oidc'; -import { AuthService, IAbpGuard } from '@abp/ng.core'; +import { AuthService, IAbpGuard, EnvironmentService } from '@abp/ng.core'; /** * @deprecated Use `abpOAuthGuard` *function* instead. @@ -58,14 +58,17 @@ export const asyncAbpOAuthGuard: CanActivateFn = ( route: ActivatedRouteSnapshot, state: RouterStateSnapshot, ) => { + const oAuthService = inject(OAuthService); const authService = inject(AuthService); - const code = new URLSearchParams(window.location.search).get('code'); + const environmentService = inject(EnvironmentService); + + const { oAuthConfig } = environmentService.getEnvironment(); - if (code) { + if (oAuthConfig?.responseType === 'code') { return firstValueFrom( - interval(100).pipe( - map(() => authService.isAuthenticated), - filter(isAuthenticated => isAuthenticated), + timer(0, 100).pipe( + map(() => oAuthService.hasValidAccessToken()), + filter(Boolean), take(1), timeout(3000), catchError(() => { @@ -76,7 +79,7 @@ export const asyncAbpOAuthGuard: CanActivateFn = ( ); } - if (authService.isAuthenticated) { + if (oAuthService.hasValidAccessToken()) { return true; }