Fix OIDC auto-login not triggering in new browser tabs

This commit is contained in:
aditya.chandel
2025-08-12 22:41:37 -06:00
committed by Aditya Chandel
parent e41ecb49d0
commit 22b2c013bd
4 changed files with 59 additions and 89 deletions

View File

@@ -1,19 +1,12 @@
import {Injectable} from '@angular/core';
import {BehaviorSubject} from 'rxjs';
@Injectable({ providedIn: 'root' })
@Injectable({providedIn: 'root'})
export class AuthInitializationService {
private initialized = new BehaviorSubject<boolean>(false);
initialized$ = this.initialized.asObservable();
private oidcFailed = new BehaviorSubject<boolean>(false);
oidcFailed$ = this.oidcFailed.asObservable();
markAsInitialized() {
this.initialized.next(true);
}
setOidcFailed(failed: boolean) {
this.oidcFailed.next(failed);
}
}

View File

@@ -16,59 +16,52 @@ export function initializeAuthFactory() {
return new Promise<void>((resolve) => {
const sub = appSettingsService.appSettings$.subscribe(settings => {
if (!settings) return;
if (settings) {
if (settings.oidcEnabled && settings.oidcProviderDetails) {
const details = settings.oidcProviderDetails;
sub.unsubscribe();
if (settings.oidcEnabled && settings.oidcProviderDetails) {
const details = settings.oidcProviderDetails;
oauthService.configure({
issuer: details.issuerUri,
clientId: details.clientId,
scope: 'openid profile email offline_access',
redirectUri: window.location.origin + '/oauth2-callback',
responseType: 'code',
showDebugInformation: false,
requireHttps: false,
strictDiscoveryDocumentValidation: false,
});
oauthService.loadDiscoveryDocumentAndTryLogin()
.then(() => {
if (oauthService.hasValidAccessToken()) {
console.log('[OIDC] Valid access token found');
oauthService.setupAutomaticSilentRefresh();
websocketInitializer(authService);
} else {
console.warn('[OIDC] No valid access token. Will proceed to app and show login page.');
}
})
.catch(err => {
console.error('[OIDC] Failed to load discovery document or login:', err);
authInitService.setOidcFailed(true);
})
.finally(() => {
authInitService.markAsInitialized();
resolve();
oauthService.configure({
issuer: details.issuerUri,
clientId: details.clientId,
scope: 'openid profile email offline_access',
redirectUri: window.location.origin + '/oauth2-callback',
responseType: 'code',
showDebugInformation: false,
requireHttps: false,
strictDiscoveryDocumentValidation: false,
});
} else if (settings.remoteAuthEnabled) {
authService.remoteLogin().subscribe({
next: () => {
authInitService.markAsInitialized();
resolve();
},
error: err => {
console.error('[Remote Login] failed:', err);
authInitService.markAsInitialized();
resolve();
}
});
} else {
authInitService.markAsInitialized();
resolve();
oauthService.loadDiscoveryDocumentAndTryLogin()
.then(() => {
console.log('[OIDC] Discovery document loaded and login attempted');
if (oauthService.hasValidAccessToken()) {
authService.tokenSubject.next(oauthService.getAccessToken())
console.log('[OIDC] Valid access token found after tryLogin');
router.navigate(['/dashboard']);
oauthService.setupAutomaticSilentRefresh();
websocketInitializer(authService);
authInitService.markAsInitialized();
resolve();
} else {
console.log('[OIDC] No valid access token found, attempting silent login with prompt=none');
oauthService.initImplicitFlow();
resolve();
}
})
.catch(err => {
authInitService.markAsInitialized();
console.error(
'OIDC initialization failed: Unable to complete OpenID Connect discovery or login. ' +
'This may be due to an incorrect issuer URL, client ID, or network issue. ' +
'Falling back to local login. Details:', err
);
resolve();
});
} else {
authInitService.markAsInitialized();
resolve();
}
sub.unsubscribe();
}
});
});

View File

@@ -20,11 +20,9 @@ export class AuthService {
private oAuthService = inject(OAuthService);
private router = inject(Router);
private tokenSubject = new BehaviorSubject<string | null>(this.getOidcAccessToken() || this.getInternalAccessToken());
public tokenSubject = new BehaviorSubject<string | null>(this.getOidcAccessToken() || this.getInternalAccessToken());
public token$ = this.tokenSubject.asObservable();
private logoutSubject = new Subject<void>();
public logout$ = this.logoutSubject.asObservable();
internalLogin(credentials: { username: string; password: string }): Observable<{ accessToken: string; refreshToken: string, isDefaultPassword: string }> {
return this.http.post<{ accessToken: string; refreshToken: string, isDefaultPassword: string }>(`${this.apiUrl}/login`, credentials).pipe(
@@ -48,17 +46,6 @@ export class AuthService {
);
}
remoteLogin(): Observable<{ accessToken: string; refreshToken: string, isDefaultPassword: string }> {
return this.http.get<{ accessToken: string; refreshToken: string, isDefaultPassword: string }>(`${this.apiUrl}/remote`).pipe(
tap((response) => {
if (response.accessToken && response.refreshToken) {
this.saveInternalTokens(response.accessToken, response.refreshToken);
this.initializeWebSocketConnection();
}
})
);
}
saveInternalTokens(accessToken: string, refreshToken: string): void {
localStorage.setItem('accessToken_Internal', accessToken);
localStorage.setItem('refreshToken_Internal', refreshToken);
@@ -81,13 +68,8 @@ export class AuthService {
localStorage.removeItem('accessToken_Internal');
localStorage.removeItem('refreshToken_Internal');
this.tokenSubject.next(null);
this.logoutSubject.next();
this.getRxStompService().deactivate();
if (this.oAuthService.clientId) {
this.oAuthService.logOut();
} else {
this.router.navigate(['/login']);
}
this.router.navigate(['/login']);
}
getRxStompService(): RxStompService {

View File

@@ -1,26 +1,28 @@
import { Injectable, inject } from '@angular/core';
import { AuthService } from './auth.service';
import { UserService } from '../../settings/user-management/user.service';
import { filter, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
import {Injectable, inject} from '@angular/core';
import {AuthService} from './auth.service';
import {UserService} from '../../settings/user-management/user.service';
import {filter, catchError} from 'rxjs/operators';
import {of} from 'rxjs';
import {OAuthService} from 'angular-oauth2-oidc';
@Injectable({ providedIn: 'root' })
@Injectable({providedIn: 'root'})
export class StartupService {
private auth = inject(AuthService);
private userSvc = inject(UserService);
private authService = inject(AuthService);
private userService = inject(UserService);
load(): Promise<void> {
this.auth.token$
this.authService.token$
.pipe(filter(t => !!t))
.subscribe(() => {
this.userSvc.getMyself()
this.userService.getMyself()
.pipe(catchError(() => of(null)))
.subscribe(user => {
if (user) {
this.userSvc.setInitialUser(user);
this.userService.setInitialUser(user);
}
});
});
return Promise.resolve();
}
}