oidc-client-rx/src/flows/callback-handling/user-callback-handler.service.ts
2025-01-31 05:57:51 +08:00

133 lines
4.1 KiB
TypeScript

import { Injectable, inject } from 'injection-js';
import { type Observable, of, throwError } from 'rxjs';
import { catchError, switchMap } from 'rxjs/operators';
import { AuthStateService } from '../../auth-state/auth-state.service';
import type { OpenIdConfiguration } from '../../config/openid-configuration';
import { LoggerService } from '../../logging/logger.service';
import { UserService } from '../../user-data/user.service';
import type { StateValidationResult } from '../../validation/state-validation-result';
import type { CallbackContext } from '../callback-context';
import { FlowsDataService } from '../flows-data.service';
import { ResetAuthDataService } from '../reset-auth-data.service';
@Injectable()
export class UserCallbackHandlerService {
private readonly loggerService = inject(LoggerService);
private readonly authStateService = inject(AuthStateService);
private readonly flowsDataService = inject(FlowsDataService);
private readonly userService = inject(UserService);
private readonly resetAuthDataService = inject(ResetAuthDataService);
// STEP 5 userData
callbackUser(
callbackContext: CallbackContext,
configuration: OpenIdConfiguration,
allConfigs: OpenIdConfiguration[]
): Observable<CallbackContext> {
const { isRenewProcess, validationResult, authResult, refreshToken } =
callbackContext;
const { autoUserInfo, renewUserInfoAfterTokenRenew } = configuration;
if (!autoUserInfo) {
if (!isRenewProcess || renewUserInfoAfterTokenRenew) {
// userData is set to the id_token decoded, auto get user data set to false
// biome-ignore lint/nursery/useCollapsedIf: <explanation>
if (validationResult?.decodedIdToken) {
this.userService.setUserDataToStore(
validationResult.decodedIdToken,
configuration,
allConfigs
);
}
}
if (!isRenewProcess && !refreshToken) {
this.flowsDataService.setSessionState(
authResult?.session_state,
configuration
);
}
this.publishAuthState(validationResult, isRenewProcess);
return of(callbackContext);
}
return this.userService
.getAndPersistUserDataInStore(
configuration,
allConfigs,
isRenewProcess,
validationResult?.idToken,
validationResult?.decodedIdToken
)
.pipe(
switchMap((userData) => {
if (userData) {
if (!refreshToken) {
this.flowsDataService.setSessionState(
authResult?.session_state,
configuration
);
}
this.publishAuthState(validationResult, isRenewProcess);
return of(callbackContext);
}
this.resetAuthDataService.resetAuthorizationData(
configuration,
allConfigs
);
this.publishUnauthenticatedState(validationResult, isRenewProcess);
const errorMessage = `Called for userData but they were ${userData}`;
this.loggerService.logWarning(configuration, errorMessage);
return throwError(() => new Error(errorMessage));
}),
catchError((err) => {
const errorMessage = `Failed to retrieve user info with error: ${err}`;
this.loggerService.logWarning(configuration, errorMessage);
return throwError(() => new Error(errorMessage));
})
);
}
private publishAuthState(
stateValidationResult: StateValidationResult | null,
isRenewProcess: boolean
): void {
if (!stateValidationResult) {
return;
}
this.authStateService.updateAndPublishAuthState({
isAuthenticated: true,
validationResult: stateValidationResult.state,
isRenewProcess,
});
}
private publishUnauthenticatedState(
stateValidationResult: StateValidationResult | null,
isRenewProcess: boolean
): void {
if (!stateValidationResult) {
return;
}
this.authStateService.updateAndPublishAuthState({
isAuthenticated: false,
validationResult: stateValidationResult.state,
isRenewProcess,
});
}
}