UNPKG

angular-auth-oidc-client

Version:
1 lines 539 kB
{"version":3,"file":"angular-auth-oidc-client.mjs","sources":["../../../projects/angular-auth-oidc-client/src/lib/config/loader/config-loader.ts","../../../projects/angular-auth-oidc-client/src/lib/auth-config.ts","../../../projects/angular-auth-oidc-client/src/lib/logging/abstract-logger.service.ts","../../../projects/angular-auth-oidc-client/src/lib/logging/console-logger.service.ts","../../../projects/angular-auth-oidc-client/src/lib/logging/log-level.ts","../../../projects/angular-auth-oidc-client/src/lib/logging/logger.service.ts","../../../projects/angular-auth-oidc-client/src/lib/public-events/event-types.ts","../../../projects/angular-auth-oidc-client/src/lib/public-events/public-events.service.ts","../../../projects/angular-auth-oidc-client/src/lib/storage/abstract-security-storage.ts","../../../projects/angular-auth-oidc-client/src/lib/storage/browser-storage.service.ts","../../../projects/angular-auth-oidc-client/src/lib/storage/storage-persistence.service.ts","../../../projects/angular-auth-oidc-client/src/lib/extractors/jwk.extractor.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/tokenHelper/token-helper.service.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/crypto/crypto.service.ts","../../../projects/angular-auth-oidc-client/src/lib/validation/jwk-window-crypto.service.ts","../../../projects/angular-auth-oidc-client/src/lib/validation/jwt-window-crypto.service.ts","../../../projects/angular-auth-oidc-client/src/lib/validation/token-validation.helper.ts","../../../projects/angular-auth-oidc-client/src/lib/validation/token-validation.service.ts","../../../projects/angular-auth-oidc-client/src/lib/auth-state/auth-state.service.ts","../../../projects/angular-auth-oidc-client/src/lib/auto-login/auto-login.service.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/flowHelper/flow-helper.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/random/random.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/flows-data.service.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/url/uri-encoder.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/url/url.service.ts","../../../projects/angular-auth-oidc-client/src/lib/api/http-base.service.ts","../../../projects/angular-auth-oidc-client/src/lib/api/data.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/callback-handling/error-helper.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/callback-handling/code-flow-callback-handler.service.ts","../../../projects/angular-auth-oidc-client/src/lib/validation/validation-result.ts","../../../projects/angular-auth-oidc-client/src/lib/user-data/user.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/reset-auth-data.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/signin-key-data.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/callback-handling/history-jwt-keys-callback-handler.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/callback-handling/implicit-flow-callback-handler.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-session-callback-handler.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/callback-handling/refresh-token-callback-handler.service.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/equality/equality.service.ts","../../../projects/angular-auth-oidc-client/src/lib/validation/state-validation-result.ts","../../../projects/angular-auth-oidc-client/src/lib/validation/state-validation.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/callback-handling/state-validation-callback-handler.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/callback-handling/user-callback-handler.service.ts","../../../projects/angular-auth-oidc-client/src/lib/flows/flows.service.ts","../../../projects/angular-auth-oidc-client/src/lib/callback/interval.service.ts","../../../projects/angular-auth-oidc-client/src/lib/callback/code-flow-callback.service.ts","../../../projects/angular-auth-oidc-client/src/lib/callback/implicit-flow-callback.service.ts","../../../projects/angular-auth-oidc-client/src/lib/callback/callback.service.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/platform-provider/platform.provider.ts","../../../projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known-data.service.ts","../../../projects/angular-auth-oidc-client/src/lib/config/auth-well-known/auth-well-known.service.ts","../../../projects/angular-auth-oidc-client/src/lib/config/default-config.ts","../../../projects/angular-auth-oidc-client/src/lib/config/validation/rule.ts","../../../projects/angular-auth-oidc-client/src/lib/config/validation/rules/ensure-authority.rule.ts","../../../projects/angular-auth-oidc-client/src/lib/config/validation/rules/ensure-clientId.rule.ts","../../../projects/angular-auth-oidc-client/src/lib/config/validation/rules/ensure-no-duplicated-configs.rule.ts","../../../projects/angular-auth-oidc-client/src/lib/config/validation/rules/ensure-redirect-url.rule.ts","../../../projects/angular-auth-oidc-client/src/lib/config/validation/rules/ensure-silentRenewUrl-with-no-refreshtokens.rule.ts","../../../projects/angular-auth-oidc-client/src/lib/config/validation/rules/use-offline-scope-with-silent-renew.rule.ts","../../../projects/angular-auth-oidc-client/src/lib/config/validation/rules/index.ts","../../../projects/angular-auth-oidc-client/src/lib/config/validation/config-validation.service.ts","../../../projects/angular-auth-oidc-client/src/lib/config/config.service.ts","../../../projects/angular-auth-oidc-client/src/lib/iframe/existing-iframe.service.ts","../../../projects/angular-auth-oidc-client/src/lib/iframe/silent-renew.service.ts","../../../projects/angular-auth-oidc-client/src/lib/iframe/refresh-session-iframe.service.ts","../../../projects/angular-auth-oidc-client/src/lib/callback/refresh-session-refresh-token.service.ts","../../../projects/angular-auth-oidc-client/src/lib/callback/periodically-token-check.service.ts","../../../projects/angular-auth-oidc-client/src/lib/callback/refresh-session.service.ts","../../../projects/angular-auth-oidc-client/src/lib/iframe/check-session.service.ts","../../../projects/angular-auth-oidc-client/src/lib/login/popup/popup.service.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/url/current-url.service.ts","../../../projects/angular-auth-oidc-client/src/lib/auth-state/check-auth.service.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/redirect/redirect.service.ts","../../../projects/angular-auth-oidc-client/src/lib/login/response-type-validation/response-type-validation.service.ts","../../../projects/angular-auth-oidc-client/src/lib/login/par/par.service.ts","../../../projects/angular-auth-oidc-client/src/lib/login/par/par-login.service.ts","../../../projects/angular-auth-oidc-client/src/lib/login/popup/popup-login.service.ts","../../../projects/angular-auth-oidc-client/src/lib/login/standard/standard-login.service.ts","../../../projects/angular-auth-oidc-client/src/lib/login/login.service.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/object/object.helper.ts","../../../projects/angular-auth-oidc-client/src/lib/logoff-revoke/logoff-revocation.service.ts","../../../projects/angular-auth-oidc-client/src/lib/oidc.security.service.ts","../../../projects/angular-auth-oidc-client/src/lib/storage/default-sessionstorage.service.ts","../../../projects/angular-auth-oidc-client/src/lib/provide-auth.ts","../../../projects/angular-auth-oidc-client/src/lib/auth.module.ts","../../../projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-all-routes.guard.ts","../../../projects/angular-auth-oidc-client/src/lib/auto-login/auto-login-partial-routes.guard.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/collections/collections.helper.ts","../../../projects/angular-auth-oidc-client/src/lib/utils/regex/regex.helper.ts","../../../projects/angular-auth-oidc-client/src/lib/interceptor/closest-matching-route.service.ts","../../../projects/angular-auth-oidc-client/src/lib/interceptor/auth.interceptor.ts","../../../projects/angular-auth-oidc-client/src/lib/storage/default-localstorage.service.ts","../../../projects/angular-auth-oidc-client/src/lib/index.ts","../../../projects/angular-auth-oidc-client/src/public-api.ts","../../../projects/angular-auth-oidc-client/src/angular-auth-oidc-client.ts"],"sourcesContent":["import { Provider } from '@angular/core';\nimport { forkJoin, Observable, of } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { OpenIdConfiguration } from '../openid-configuration';\n\nexport class OpenIdConfigLoader {\n loader?: Provider;\n}\n\nexport abstract class StsConfigLoader {\n abstract loadConfigs(): Observable<OpenIdConfiguration[]>;\n}\n\nexport class StsConfigStaticLoader implements StsConfigLoader {\n constructor(\n private readonly passedConfigs: OpenIdConfiguration | OpenIdConfiguration[]\n ) {}\n\n loadConfigs(): Observable<OpenIdConfiguration[]> {\n if (Array.isArray(this.passedConfigs)) {\n return of(this.passedConfigs);\n }\n\n return of([this.passedConfigs]);\n }\n}\n\nexport class StsConfigHttpLoader implements StsConfigLoader {\n constructor(\n private readonly configs$:\n | Observable<OpenIdConfiguration>\n | Observable<OpenIdConfiguration>[]\n | Observable<OpenIdConfiguration[]>\n ) {}\n\n loadConfigs(): Observable<OpenIdConfiguration[]> {\n if (Array.isArray(this.configs$)) {\n return forkJoin(this.configs$);\n }\n\n const singleConfigOrArray = this.configs$ as Observable<unknown>;\n\n return singleConfigOrArray.pipe(\n map((value: unknown) => {\n if (Array.isArray(value)) {\n return value as OpenIdConfiguration[];\n }\n\n return [value] as OpenIdConfiguration[];\n })\n );\n }\n}\n","import { InjectionToken, Provider } from '@angular/core';\nimport {\n StsConfigLoader,\n StsConfigStaticLoader,\n} from './config/loader/config-loader';\nimport { OpenIdConfiguration } from './config/openid-configuration';\n\nexport interface PassedInitialConfig {\n config?: OpenIdConfiguration | OpenIdConfiguration[];\n loader?: Provider;\n}\n\nexport function createStaticLoader(\n passedConfig: PassedInitialConfig\n): StsConfigLoader {\n if (!passedConfig?.config) {\n throw new Error('No config provided!');\n }\n\n return new StsConfigStaticLoader(passedConfig.config);\n}\n\nexport const PASSED_CONFIG = new InjectionToken<PassedInitialConfig>(\n 'PASSED_CONFIG'\n);\n","import { Injectable } from '@angular/core';\r\n\r\n/**\r\n * Implement this class-interface to create a custom logger service.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport abstract class AbstractLoggerService {\r\n abstract logError(message: string | object, ...args: any[]): void;\r\n\r\n abstract logWarning(message: string | object, ...args: any[]): void;\r\n\r\n abstract logDebug(message: string | object, ...args: any[]): void;\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { AbstractLoggerService } from './abstract-logger.service';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class ConsoleLoggerService implements AbstractLoggerService {\r\n logError(message: string | object, ...args: any[]): void {\r\n console.error(message, ...args);\r\n }\r\n\r\n logWarning(message: string | object, ...args: any[]): void {\r\n console.warn(message, ...args);\r\n }\r\n\r\n logDebug(message: string | object, ...args: any[]): void {\r\n console.debug(message, ...args);\r\n }\r\n}\r\n","export enum LogLevel {\n None,\n Debug,\n Warn,\n Error,\n}\n","import { Injectable, inject } from '@angular/core';\r\nimport { OpenIdConfiguration } from '../config/openid-configuration';\r\nimport { AbstractLoggerService } from './abstract-logger.service';\r\nimport { LogLevel } from './log-level';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class LoggerService {\r\n private readonly abstractLoggerService = inject(AbstractLoggerService);\r\n\r\n logError(\r\n configuration: OpenIdConfiguration,\r\n message: string | object,\r\n ...args: any[]\r\n ): void {\r\n if (this.loggingIsTurnedOff(configuration)) {\r\n return;\r\n }\r\n\r\n const { configId } = configuration;\r\n const messageToLog = this.isObject(message)\r\n ? JSON.stringify(message)\r\n : message;\r\n\r\n if (!!args && !!args.length) {\r\n this.abstractLoggerService.logError(\r\n `[ERROR] ${configId} - ${messageToLog}`,\r\n ...args\r\n );\r\n } else {\r\n this.abstractLoggerService.logError(\r\n `[ERROR] ${configId} - ${messageToLog}`\r\n );\r\n }\r\n }\r\n\r\n logWarning(\r\n configuration: OpenIdConfiguration,\r\n message: string | object,\r\n ...args: any[]\r\n ): void {\r\n if (!this.logLevelIsSet(configuration)) {\r\n return;\r\n }\r\n\r\n if (this.loggingIsTurnedOff(configuration)) {\r\n return;\r\n }\r\n\r\n if (\r\n !this.currentLogLevelIsEqualOrSmallerThan(configuration, LogLevel.Warn)\r\n ) {\r\n return;\r\n }\r\n\r\n const { configId } = configuration;\r\n const messageToLog = this.isObject(message)\r\n ? JSON.stringify(message)\r\n : message;\r\n\r\n if (!!args && !!args.length) {\r\n this.abstractLoggerService.logWarning(\r\n `[WARN] ${configId} - ${messageToLog}`,\r\n ...args\r\n );\r\n } else {\r\n this.abstractLoggerService.logWarning(\r\n `[WARN] ${configId} - ${messageToLog}`\r\n );\r\n }\r\n }\r\n\r\n logDebug(\r\n configuration: OpenIdConfiguration | null,\r\n message: string | object,\r\n ...args: any[]\r\n ): void {\r\n if (!configuration) {\r\n return;\r\n }\r\n\r\n if (!this.logLevelIsSet(configuration)) {\r\n return;\r\n }\r\n\r\n if (this.loggingIsTurnedOff(configuration)) {\r\n return;\r\n }\r\n\r\n if (\r\n !this.currentLogLevelIsEqualOrSmallerThan(configuration, LogLevel.Debug)\r\n ) {\r\n return;\r\n }\r\n\r\n const { configId } = configuration;\r\n const messageToLog = this.isObject(message)\r\n ? JSON.stringify(message)\r\n : message;\r\n\r\n if (!!args && !!args.length) {\r\n this.abstractLoggerService.logDebug(\r\n `[DEBUG] ${configId} - ${messageToLog}`,\r\n ...args\r\n );\r\n } else {\r\n this.abstractLoggerService.logDebug(\r\n `[DEBUG] ${configId} - ${messageToLog}`\r\n );\r\n }\r\n }\r\n\r\n private currentLogLevelIsEqualOrSmallerThan(\r\n configuration: OpenIdConfiguration,\r\n logLevelToCompare: LogLevel\r\n ): boolean {\r\n const { logLevel } = configuration || {};\r\n\r\n if (!logLevel) {\r\n return false;\r\n }\r\n\r\n return logLevel <= logLevelToCompare;\r\n }\r\n\r\n private logLevelIsSet(configuration: OpenIdConfiguration): boolean {\r\n const { logLevel } = configuration || {};\r\n\r\n if (logLevel === null) {\r\n return false;\r\n }\r\n\r\n return logLevel !== undefined;\r\n }\r\n\r\n private loggingIsTurnedOff(configuration: OpenIdConfiguration): boolean {\r\n const { logLevel } = configuration || {};\r\n\r\n return logLevel === LogLevel.None;\r\n }\r\n\r\n private isObject(possibleObject: any): boolean {\r\n return Object.prototype.toString.call(possibleObject) === '[object Object]';\r\n }\r\n}\r\n","export enum EventTypes {\n /**\n * This only works in the AppModule Constructor\n */\n ConfigLoaded,\n CheckingAuth,\n CheckingAuthFinished,\n CheckingAuthFinishedWithError,\n ConfigLoadingFailed,\n CheckSessionReceived,\n UserDataChanged,\n NewAuthenticationResult,\n TokenExpired,\n IdTokenExpired,\n SilentRenewStarted,\n SilentRenewFailed,\n}\n","import { Injectable } from '@angular/core';\nimport { Observable, ReplaySubject } from 'rxjs';\nimport { EventTypes } from './event-types';\nimport { OidcClientNotification } from './notification';\n\n@Injectable({ providedIn: 'root' })\nexport class PublicEventsService {\n private readonly notify = new ReplaySubject<OidcClientNotification<any>>(1);\n\n /**\n * Fires a new event.\n *\n * @param type The event type.\n * @param value The event value.\n */\n fireEvent<T>(type: EventTypes, value?: T): void {\n this.notify.next({ type, value });\n }\n\n /**\n * Wires up the event notification observable.\n */\n registerForEvents(): Observable<OidcClientNotification<any>> {\n return this.notify.asObservable();\n }\n}\n","import { Injectable } from '@angular/core';\r\n\r\n/**\r\n * Implement this class-interface to create a custom storage.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport abstract class AbstractSecurityStorage {\r\n /**\r\n * This method must contain the logic to read the storage.\r\n *\r\n * @return The value of the given key\r\n */\r\n abstract read(key: string): string | null;\r\n\r\n /**\r\n * This method must contain the logic to write the storage.\r\n *\r\n * @param key The key to write a value for\r\n * @param value The value for the given key\r\n */\r\n abstract write(key: string, value: string): void;\r\n\r\n /**\r\n * This method must contain the logic to remove an item from the storage.\r\n *\r\n * @param key The value for the key to be removed\r\n */\r\n abstract remove(key: string): void;\r\n\r\n /**\r\n * This method must contain the logic to remove all items from the storage.\r\n */\r\n abstract clear(): void;\r\n}\r\n","import { inject, Injectable } from '@angular/core';\r\nimport { OpenIdConfiguration } from '../config/openid-configuration';\r\nimport { LoggerService } from '../logging/logger.service';\r\nimport { AbstractSecurityStorage } from './abstract-security-storage';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class BrowserStorageService {\r\n private readonly loggerService = inject(LoggerService);\r\n private readonly abstractSecurityStorage = inject(AbstractSecurityStorage);\r\n\r\n read(key: string, configuration: OpenIdConfiguration): any {\r\n const { configId } = configuration;\r\n\r\n if (!configId) {\r\n this.loggerService.logDebug(\r\n configuration,\r\n `Wanted to read '${key}' but configId was '${configId}'`\r\n );\r\n\r\n return null;\r\n }\r\n\r\n if (!this.hasStorage()) {\r\n this.loggerService.logDebug(\r\n configuration,\r\n `Wanted to read '${key}' but Storage was undefined`\r\n );\r\n\r\n return null;\r\n }\r\n\r\n const storedConfig = this.abstractSecurityStorage.read(configId);\r\n\r\n if (!storedConfig) {\r\n return null;\r\n }\r\n\r\n return JSON.parse(storedConfig);\r\n }\r\n\r\n write(value: any, configuration: OpenIdConfiguration): boolean {\r\n const { configId } = configuration;\r\n\r\n if (!configId) {\r\n this.loggerService.logDebug(\r\n configuration,\r\n `Wanted to write but configId was '${configId}'`\r\n );\r\n\r\n return false;\r\n }\r\n\r\n if (!this.hasStorage()) {\r\n this.loggerService.logDebug(\r\n configuration,\r\n `Wanted to write but Storage was falsy`\r\n );\r\n\r\n return false;\r\n }\r\n\r\n value = value || null;\r\n\r\n this.abstractSecurityStorage.write(configId, JSON.stringify(value));\r\n\r\n return true;\r\n }\r\n\r\n remove(key: string, configuration: OpenIdConfiguration): boolean {\r\n if (!this.hasStorage()) {\r\n this.loggerService.logDebug(\r\n configuration,\r\n `Wanted to remove '${key}' but Storage was falsy`\r\n );\r\n\r\n return false;\r\n }\r\n\r\n // const storage = this.getStorage(configuration);\r\n // if (!storage) {\r\n // this.loggerService.logDebug(configuration, `Wanted to write '${key}' but Storage was falsy`);\r\n\r\n // return false;\r\n // }\r\n\r\n this.abstractSecurityStorage.remove(key);\r\n\r\n return true;\r\n }\r\n\r\n // TODO THIS STORAGE WANTS AN ID BUT CLEARS EVERYTHING\r\n clear(configuration: OpenIdConfiguration): boolean {\r\n if (!this.hasStorage()) {\r\n this.loggerService.logDebug(\r\n configuration,\r\n `Wanted to clear storage but Storage was falsy`\r\n );\r\n\r\n return false;\r\n }\r\n\r\n // const storage = this.getStorage(configuration);\r\n // if (!storage) {\r\n // this.loggerService.logDebug(configuration, `Wanted to clear storage but Storage was falsy`);\r\n\r\n // return false;\r\n // }\r\n\r\n this.abstractSecurityStorage.clear();\r\n\r\n return true;\r\n }\r\n\r\n private hasStorage(): boolean {\r\n return typeof Storage !== 'undefined';\r\n }\r\n}\r\n","import { Injectable, inject } from '@angular/core';\nimport { AuthResult } from '../flows/callback-context';\nimport { OpenIdConfiguration } from './../config/openid-configuration';\nimport { BrowserStorageService } from './browser-storage.service';\n\nexport type StorageKeys =\n | 'authnResult'\n | 'authzData'\n | 'access_token_expires_at'\n | 'authWellKnownEndPoints'\n | 'userData'\n | 'authNonce'\n | 'codeVerifier'\n | 'authStateControl'\n | 'reusable_refresh_token'\n | 'session_state'\n | 'storageSilentRenewRunning'\n | 'storageCodeFlowInProgress'\n | 'storageCustomParamsAuthRequest'\n | 'storageCustomParamsRefresh'\n | 'storageCustomParamsEndSession'\n | 'redirect'\n | 'configIds'\n | 'jwtKeys'\n | 'popupauth';\n\n@Injectable({ providedIn: 'root' })\nexport class StoragePersistenceService {\n private readonly browserStorageService = inject(BrowserStorageService);\n\n read(key: StorageKeys, config: OpenIdConfiguration): any {\n const storedConfig = this.browserStorageService.read(key, config) || {};\n\n return storedConfig[key];\n }\n\n write(key: StorageKeys, value: any, config: OpenIdConfiguration): boolean {\n const storedConfig = this.browserStorageService.read(key, config) || {};\n\n storedConfig[key] = value;\n\n return this.browserStorageService.write(storedConfig, config);\n }\n\n remove(key: StorageKeys, config: OpenIdConfiguration): void {\n const storedConfig = this.browserStorageService.read(key, config) || {};\n\n delete storedConfig[key];\n\n this.browserStorageService.write(storedConfig, config);\n }\n\n clear(config: OpenIdConfiguration): void {\n this.browserStorageService.clear(config);\n }\n\n resetStorageFlowData(config: OpenIdConfiguration): void {\n this.remove('session_state', config);\n this.remove('storageSilentRenewRunning', config);\n this.remove('storageCodeFlowInProgress', config);\n this.remove('codeVerifier', config);\n this.remove('userData', config);\n this.remove('storageCustomParamsAuthRequest', config);\n this.remove('access_token_expires_at', config);\n this.remove('storageCustomParamsRefresh', config);\n this.remove('storageCustomParamsEndSession', config);\n this.remove('reusable_refresh_token', config);\n }\n\n resetAuthStateInStorage(config: OpenIdConfiguration): void {\n this.remove('authzData', config);\n this.remove('reusable_refresh_token', config);\n this.remove('authnResult', config);\n }\n\n getAccessToken(config: OpenIdConfiguration): string {\n return this.read('authzData', config);\n }\n\n getIdToken(config: OpenIdConfiguration): string {\n return this.read('authnResult', config)?.id_token;\n }\n\n getRefreshToken(config: OpenIdConfiguration): string {\n const refreshToken = this.read('authnResult', config)?.refresh_token;\n\n if (!refreshToken && config.allowUnsafeReuseRefreshToken) {\n return this.read('reusable_refresh_token', config);\n }\n\n return refreshToken;\n }\n\n getAuthenticationResult(config: OpenIdConfiguration): AuthResult {\n return this.read('authnResult', config);\n }\n}\n","import { Injectable } from '@angular/core';\n\n@Injectable({ providedIn: 'root' })\nexport class JwkExtractor {\n extractJwk(\n keys: JsonWebKey[],\n spec?: { kid?: string; use?: string; kty?: string },\n throwOnEmpty = true\n ): JsonWebKey[] {\n if (0 === keys.length) {\n throw JwkExtractorInvalidArgumentError;\n }\n\n const foundKeys = keys\n .filter((k) => (spec?.kid ? (k as any)['kid'] === spec.kid : true))\n .filter((k) => (spec?.use ? k['use'] === spec.use : true))\n .filter((k) => (spec?.kty ? k['kty'] === spec.kty : true));\n\n if (foundKeys.length === 0 && throwOnEmpty) {\n throw JwkExtractorNoMatchingKeysError;\n }\n\n if (foundKeys.length > 1 && (null === spec || undefined === spec)) {\n throw JwkExtractorSeveralMatchingKeysError;\n }\n\n return foundKeys;\n }\n}\n\nfunction buildErrorName(name: string): string {\n return JwkExtractor.name + ': ' + name;\n}\n\nexport const JwkExtractorInvalidArgumentError = {\n name: buildErrorName('InvalidArgumentError'),\n message: 'Array of keys was empty. Unable to extract',\n};\n\nexport const JwkExtractorNoMatchingKeysError = {\n name: buildErrorName('NoMatchingKeysError'),\n message: 'No key found matching the spec',\n};\n\nexport const JwkExtractorSeveralMatchingKeysError = {\n name: buildErrorName('SeveralMatchingKeysError'),\n message: 'More than one key found. Please use spec to filter',\n};\n","import { DOCUMENT } from '@angular/common';\r\nimport { inject, Injectable } from '@angular/core';\r\nimport { OpenIdConfiguration } from '../../config/openid-configuration';\r\nimport { LoggerService } from '../../logging/logger.service';\r\n\r\nconst PARTS_OF_TOKEN = 3;\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class TokenHelperService {\r\n private readonly loggerService = inject(LoggerService);\r\n private readonly document = inject<Document>(DOCUMENT);\r\n\r\n getTokenExpirationDate(dataIdToken: any): Date {\r\n if (!Object.prototype.hasOwnProperty.call(dataIdToken, 'exp')) {\r\n return new Date(new Date().toUTCString());\r\n }\r\n\r\n const date = new Date(0); // The 0 here is the key, which sets the date to the epoch\r\n\r\n date.setUTCSeconds(dataIdToken.exp);\r\n\r\n return date;\r\n }\r\n\r\n getSigningInputFromToken(\r\n token: string | undefined | null,\r\n encoded: boolean,\r\n configuration: OpenIdConfiguration\r\n ): string {\r\n if (!this.tokenIsValid(token, configuration)) {\r\n return '';\r\n }\r\n\r\n const header: string = this.getHeaderFromToken(\r\n token,\r\n encoded,\r\n configuration\r\n );\r\n const payload: string = this.getPayloadFromToken(\r\n token,\r\n encoded,\r\n configuration\r\n );\r\n\r\n return [header, payload].join('.');\r\n }\r\n\r\n getHeaderFromToken(\r\n token: string | undefined | null,\r\n encoded: boolean,\r\n configuration: OpenIdConfiguration\r\n ): any {\r\n if (!this.tokenIsValid(token, configuration)) {\r\n return {};\r\n }\r\n\r\n return this.getPartOfToken(token, 0, encoded);\r\n }\r\n\r\n getPayloadFromToken(\r\n token: string | undefined | null,\r\n encoded: boolean,\r\n configuration: OpenIdConfiguration | null\r\n ): any {\r\n if (!configuration) {\r\n return {};\r\n }\r\n\r\n if (!this.tokenIsValid(token, configuration)) {\r\n return {};\r\n }\r\n\r\n return this.getPartOfToken(token, 1, encoded);\r\n }\r\n\r\n getSignatureFromToken(\r\n token: string | undefined | null,\r\n encoded: boolean,\r\n configuration: OpenIdConfiguration\r\n ): any {\r\n if (!this.tokenIsValid(token, configuration)) {\r\n return {};\r\n }\r\n\r\n return this.getPartOfToken(token, 2, encoded);\r\n }\r\n\r\n private getPartOfToken(token: string, index: number, encoded: boolean): any {\r\n const partOfToken = this.extractPartOfToken(token, index);\r\n\r\n if (encoded) {\r\n return partOfToken;\r\n }\r\n\r\n const result = this.urlBase64Decode(partOfToken);\r\n\r\n return JSON.parse(result);\r\n }\r\n\r\n private urlBase64Decode(str: string): string {\r\n let output = str.replace(/-/g, '+').replace(/_/g, '/');\r\n\r\n switch (output.length % 4) {\r\n case 0:\r\n break;\r\n case 2:\r\n output += '==';\r\n break;\r\n case 3:\r\n output += '=';\r\n break;\r\n default:\r\n throw Error('Illegal base64url string!');\r\n }\r\n\r\n const decoded =\r\n typeof this.document.defaultView !== 'undefined'\r\n ? this.document.defaultView?.atob(output)\r\n : Buffer.from(output, 'base64').toString('binary');\r\n\r\n if (!decoded) {\r\n return '';\r\n }\r\n\r\n try {\r\n // Going backwards: from byte stream, to percent-encoding, to original string.\r\n return decodeURIComponent(\r\n decoded\r\n .split('')\r\n .map(\r\n (c: string) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)\r\n )\r\n .join('')\r\n );\r\n } catch (err) {\r\n return decoded;\r\n }\r\n }\r\n\r\n private tokenIsValid(\r\n token: string | undefined | null,\r\n configuration: OpenIdConfiguration\r\n ): token is string {\r\n if (!token) {\r\n this.loggerService.logError(\r\n configuration,\r\n `token '${token}' is not valid --> token falsy`\r\n );\r\n\r\n return false;\r\n }\r\n\r\n if (!(token as string).includes('.')) {\r\n this.loggerService.logError(\r\n configuration,\r\n `token '${token}' is not valid --> no dots included`\r\n );\r\n\r\n return false;\r\n }\r\n\r\n const parts = token.split('.');\r\n\r\n if (parts.length !== PARTS_OF_TOKEN) {\r\n this.loggerService.logError(\r\n configuration,\r\n `token '${token}' is not valid --> token has to have exactly ${\r\n PARTS_OF_TOKEN - 1\r\n } dots`\r\n );\r\n\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n private extractPartOfToken(token: string, index: number): string {\r\n return token.split('.')[index];\r\n }\r\n}\r\n","import { DOCUMENT } from '@angular/common';\nimport { Injectable, inject } from '@angular/core';\n\n@Injectable({ providedIn: 'root' })\nexport class CryptoService {\n private readonly document = inject<Document>(DOCUMENT);\n\n getCrypto(): any {\n // support for IE, (window.crypto || window.msCrypto)\n return (\n this.document.defaultView?.crypto ||\n (this.document.defaultView as any)?.msCrypto\n );\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { CryptoService } from '../utils/crypto/crypto.service';\n\n@Injectable({ providedIn: 'root' })\nexport class JwkWindowCryptoService {\n private readonly cryptoService = inject(CryptoService);\n\n importVerificationKey(\n key: JsonWebKey,\n algorithm:\n | AlgorithmIdentifier\n | RsaHashedImportParams\n | EcKeyImportParams\n | HmacImportParams\n | AesKeyAlgorithm\n | null\n ): Promise<CryptoKey> {\n return this.cryptoService\n .getCrypto()\n .subtle.importKey('jwk', key, algorithm, false, ['verify']);\n }\n\n verifyKey(\n verifyAlgorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams | null,\n cryptoKey: CryptoKey,\n signature: BufferSource,\n signingInput: string\n ): Promise<boolean> {\n return this.cryptoService\n .getCrypto()\n .subtle.verify(\n verifyAlgorithm,\n cryptoKey,\n signature,\n new TextEncoder().encode(signingInput)\n );\n }\n}\n","import { inject, Injectable } from '@angular/core';\nimport { from, Observable } from 'rxjs';\nimport { map } from 'rxjs/operators';\nimport { CryptoService } from '../utils/crypto/crypto.service';\n\n@Injectable({ providedIn: 'root' })\nexport class JwtWindowCryptoService {\n private readonly cryptoService = inject(CryptoService);\n\n generateCodeChallenge(codeVerifier: string): Observable<string> {\n return this.calcHash(codeVerifier).pipe(\n map((challengeRaw: string) => this.base64UrlEncode(challengeRaw))\n );\n }\n\n generateAtHash(accessToken: string, algorithm: string): Observable<string> {\n return this.calcHash(accessToken, algorithm).pipe(\n map((tokenHash) => {\n const substr: string = tokenHash.substr(0, tokenHash.length / 2);\n const tokenHashBase64: string = btoa(substr);\n\n return tokenHashBase64\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n })\n );\n }\n\n private calcHash(\n valueToHash: string,\n algorithm = 'SHA-256'\n ): Observable<string> {\n const msgBuffer: Uint8Array = new TextEncoder().encode(valueToHash);\n\n return from(\n this.cryptoService.getCrypto().subtle.digest(algorithm, msgBuffer)\n ).pipe(\n map((hashBuffer: unknown) => {\n const buffer = hashBuffer as ArrayBuffer;\n const hashArray: number[] = Array.from(new Uint8Array(buffer));\n\n return this.toHashString(hashArray);\n })\n );\n }\n\n private toHashString(byteArray: number[]): string {\n let result = '';\n\n for (const e of byteArray) {\n result += String.fromCharCode(e);\n }\n\n return result;\n }\n\n private base64UrlEncode(str: string): string {\n const base64: string = btoa(str);\n\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n }\n}\n","export function getVerifyAlg(\n alg: string\n): RsaHashedImportParams | EcdsaParams | null {\n switch (alg.charAt(0)) {\n case 'R':\n return {\n name: 'RSASSA-PKCS1-v1_5',\n hash: 'SHA-256',\n };\n case 'E':\n if (alg.includes('256')) {\n return {\n name: 'ECDSA',\n hash: 'SHA-256',\n };\n } else if (alg.includes('384')) {\n return {\n name: 'ECDSA',\n hash: 'SHA-384',\n };\n } else {\n return null;\n }\n default:\n return null;\n }\n}\n\nexport function alg2kty(alg: string): string {\n switch (alg.charAt(0)) {\n case 'R':\n return 'RSA';\n\n case 'E':\n return 'EC';\n\n default:\n throw new Error('Cannot infer kty from alg: ' + alg);\n }\n}\n\nexport function getImportAlg(\n alg: string\n): RsaHashedImportParams | EcKeyImportParams | null {\n switch (alg.charAt(0)) {\n case 'R':\n if (alg.includes('256')) {\n return {\n name: 'RSASSA-PKCS1-v1_5',\n hash: 'SHA-256',\n };\n } else if (alg.includes('384')) {\n return {\n name: 'RSASSA-PKCS1-v1_5',\n hash: 'SHA-384',\n };\n } else if (alg.includes('512')) {\n return {\n name: 'RSASSA-PKCS1-v1_5',\n hash: 'SHA-512',\n };\n } else {\n return null;\n }\n case 'E':\n if (alg.includes('256')) {\n return {\n name: 'ECDSA',\n namedCurve: 'P-256',\n };\n } else if (alg.includes('384')) {\n return {\n name: 'ECDSA',\n namedCurve: 'P-384',\n };\n } else {\n return null;\n }\n default:\n return null;\n }\n}\n","import { inject, Injectable } from '@angular/core';\r\nimport { base64url } from 'rfc4648';\r\nimport { from, Observable, of } from 'rxjs';\r\nimport { map, mergeMap, tap } from 'rxjs/operators';\r\nimport { OpenIdConfiguration } from '../config/openid-configuration';\r\nimport { JwkExtractor } from '../extractors/jwk.extractor';\r\nimport { LoggerService } from '../logging/logger.service';\r\nimport { TokenHelperService } from '../utils/tokenHelper/token-helper.service';\r\nimport { JwkWindowCryptoService } from './jwk-window-crypto.service';\r\nimport { JwtWindowCryptoService } from './jwt-window-crypto.service';\r\nimport { alg2kty, getImportAlg, getVerifyAlg } from './token-validation.helper';\r\n\r\n// http://openid.net/specs/openid-connect-implicit-1_0.html\r\n\r\n// id_token\r\n// id_token C1: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery)\r\n// MUST exactly match the value of the iss (issuer) Claim.\r\n//\r\n// id_token C2: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified\r\n// by the iss (issuer) Claim as an audience.The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience,\r\n// or if it contains additional audiences not trusted by the Client.\r\n//\r\n// id_token C3: If the ID Token contains multiple audiences, the Client SHOULD verify that an azp Claim is present.\r\n//\r\n// id_token C4: If an azp (authorized party) Claim is present, the Client SHOULD verify that its client_id is the Claim Value.\r\n//\r\n// id_token C5: The Client MUST validate the signature of the ID Token according to JWS [JWS] using the algorithm specified in the\r\n// alg Header Parameter of the JOSE Header.The Client MUST use the keys provided by the Issuer.\r\n//\r\n// id_token C6: The alg value SHOULD be RS256. Validation of tokens using other signing algorithms is described in the OpenID Connect\r\n// Core 1.0\r\n// [OpenID.Core] specification.\r\n//\r\n// id_token C7: The current time MUST be before the time represented by the exp Claim (possibly allowing for some small leeway to account\r\n// for clock skew).\r\n//\r\n// id_token C8: The iat Claim can be used to reject tokens that were issued too far away from the current time,\r\n// limiting the amount of time that nonces need to be stored to prevent attacks.The acceptable range is Client specific.\r\n//\r\n// id_token C9: The value of the nonce Claim MUST be checked to verify that it is the same value as the one that was sent\r\n// in the Authentication Request.The Client SHOULD check the nonce value for replay attacks.The precise method for detecting replay attacks\r\n// is Client specific.\r\n//\r\n// id_token C10: If the acr Claim was requested, the Client SHOULD check that the asserted Claim Value is appropriate.\r\n// The meaning and processing of acr Claim Values is out of scope for this document.\r\n//\r\n// id_token C11: When a max_age request is made, the Client SHOULD check the auth_time Claim value and request re- authentication\r\n// if it determines too much time has elapsed since the last End- User authentication.\r\n\r\n// Access Token Validation\r\n// access_token C1: Hash the octets of the ASCII representation of the access_token with the hash algorithm specified in JWA[JWA]\r\n// for the alg Header Parameter of the ID Token's JOSE Header. For instance, if the alg is RS256, the hash algorithm used is SHA-256.\r\n// access_token C2: Take the left- most half of the hash and base64url- encode it.\r\n// access_token C3: The value of at_hash in the ID Token MUST match the value produced in the previous step if at_hash is present\r\n// in the ID Token.\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class TokenValidationService {\r\n static refreshTokenNoncePlaceholder = '--RefreshToken--';\r\n\r\n keyAlgorithms: string[] = [\r\n 'HS256',\r\n 'HS384',\r\n 'HS512',\r\n 'RS256',\r\n 'RS384',\r\n 'RS512',\r\n 'ES256',\r\n 'ES384',\r\n 'PS256',\r\n 'PS384',\r\n 'PS512',\r\n ];\r\n\r\n private readonly tokenHelperService = inject(TokenHelperService);\r\n private readonly loggerService = inject(LoggerService);\r\n private readonly jwkExtractor = inject(JwkExtractor);\r\n private readonly jwkWindowCryptoService = inject(JwkWindowCryptoService);\r\n private readonly jwtWindowCryptoService = inject(JwtWindowCryptoService);\r\n\r\n // id_token C7: The current time MUST be before the time represented by the exp Claim\r\n // (possibly allowing for some small leeway to account for clock skew).\r\n hasIdTokenExpired(\r\n token: string,\r\n configuration: OpenIdConfiguration,\r\n offsetSeconds?: number\r\n ): boolean {\r\n const decoded = this.tokenHelperService.getPayloadFromToken(\r\n token,\r\n false,\r\n configuration\r\n );\r\n\r\n return !this.validateIdTokenExpNotExpired(\r\n decoded,\r\n configuration,\r\n offsetSeconds\r\n );\r\n }\r\n\r\n // id_token C7: The current time MUST be before the time represented by the exp Claim\r\n // (possibly allowing for some small leeway to account for clock skew).\r\n validateIdTokenExpNotExpired(\r\n decodedIdToken: string,\r\n configuration: OpenIdConfiguration,\r\n offsetSeconds?: number\r\n ): boolean {\r\n const tokenExpirationDate =\r\n this.tokenHelperService.getTokenExpirationDate(decodedIdToken);\r\n\r\n offsetSeconds = offsetSeconds || 0;\r\n\r\n if (!tokenExpirationDate) {\r\n return false;\r\n }\r\n\r\n const tokenExpirationValue = tokenExpirationDate.valueOf();\r\n const nowWithOffset = this.calculateNowWithOffset(offsetSeconds);\r\n const tokenNotExpired = tokenExpirationValue > nowWithOffset;\r\n\r\n this.loggerService.logDebug(\r\n configuration,\r\n `Has idToken expired: ${!tokenNotExpired} --> expires in ${this.millisToMinutesAndSeconds(\r\n tokenExpirationValue - nowWithOffset\r\n )} , ${new Date(tokenExpirationValue).toLocaleTimeString()} > ${new Date(\r\n nowWithOffset\r\n ).toLocaleTimeString()}`\r\n );\r\n\r\n return tokenNotExpired;\r\n }\r\n\r\n validateAccessTokenNotExpired(\r\n accessTokenExpiresAt: Date,\r\n configuration: OpenIdConfiguration,\r\n offsetSeconds?: number\r\n ): boolean {\r\n // value is optional, so if it does not exist, then it has not expired\r\n if (!accessTokenExpiresAt) {\r\n return true;\r\n }\r\n\r\n offsetSeconds = offsetSeconds || 0;\r\n const accessTokenExpirationValue = accessTokenExpiresAt.valueOf();\r\n const nowWithOffset = this.calculateNowWithOffset(offsetSeconds);\r\n const tokenNotExpired = accessTokenExpirationValue > nowWithOffset;\r\n\r\n this.loggerService.logDebug(\r\n configuration,\r\n `Has accessToken expired: ${!tokenNotExpired} --> expires in ${this.millisToMinutesAndSeconds(\r\n accessTokenExpirationValue - nowWithOffset\r\n )} , ${new Date(\r\n accessTokenExpirationValue\r\n ).toLocaleTimeString()} > ${new Date(nowWithOffset).toLocaleTimeString()}`\r\n );\r\n\r\n return tokenNotExpired;\r\n }\r\n\r\n // iss\r\n // REQUIRED. Issuer Identifier for the Issuer of the response.The iss value is a case-sensitive URL using the\r\n // https scheme that contains scheme, host,\r\n // and optionally, port number and path components and no query or fragment components.\r\n //\r\n // sub\r\n // REQUIRED. Subject Identifier.Locally unique and never reassigned identifier within the Issuer for the End- User,\r\n // which is intended to be consumed by the Client, e.g., 24400320 or AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4.\r\n // It MUST NOT exceed 255 ASCII characters in length.The sub value is a case-sensitive string.\r\n //\r\n // aud\r\n // REQUIRED. Audience(s) that this ID Token is intended for. It MUST contain the OAuth 2.0 client_id of the Relying Party as an\r\n // audience value.\r\n // It MAY also contain identifiers for other audiences.In the general case, the aud value is an array of case-sensitive strings.\r\n // In the common special case when there is one audience, the aud value MAY be a single case-sensitive string.\r\n //\r\n // exp\r\n // REQUIRED. Expiration time on or after which the ID Token MUST NOT be accepted for processing.\r\n // The processing of this parameter requires that the current date/ time MUST be before the expiration date/ time listed in the value.\r\n // Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew.\r\n // Its value is a JSON [RFC7159] number representing the number of seconds from 1970- 01 - 01T00: 00:00Z as measured in UTC until\r\n // the date/ time.\r\n // See RFC 3339 [RFC3339] for details regarding date/ times in general and UTC in particular.\r\n //\r\n // iat\r\n // REQUIRED. Time at which the JWT was issued. Its value is a JSON number representing the number of seconds from\r\n // 1970- 01 - 01T00: 00: 00Z as measured\r\n // in UTC until the date/ time.\r\n validateRequiredIdToken(\r\n dataIdToken: any,\r\n configuration: OpenIdConfiguration\r\n ): boolean {\r\n let validated = true;\r\n\r\n if (!Object.prototype.hasOwnProperty.call(dataIdToken, 'iss')) {\r\n validated = false;\r\n this.loggerService.logWarning(\r\n configuration,\r\n 'iss is missing, this is required in the id_token'\r\n );\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(dataIdToken, 'sub')) {\r\n validated = false;\r\n this.loggerService.logWarning(\r\n configuration,\r\n 'sub is missing, this is required in the id_token'\r\n );\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(dataIdToken, 'aud')) {\r\n validated = false;\r\n this.loggerService.logWarning(\r\n configuration,\r\n 'aud is missing, this is required in the id_token'\r\n );\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(dataIdToken, 'exp')) {\r\n validated = false;\r\n this.loggerService.logWarning(\r\n configuration,\r\n 'exp is missing, this is required in the id_token'\r\n );\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(dataIdToken, 'iat')) {\r\n validated = false;\r\n this.loggerService.logWarning(\r\n configuration,\r\n 'iat is missing, this is required in the id_token'\r\n );\r\n }\r\n\r\n return validated;\r\n }\r\n\r\n // id_token C8: The iat Claim can be used to reject tokens that were issued too far away from the current time,\r\n // limiting the amount of time that nonces need to be stored to prevent attacks.The acceptable range is Client specific.\r\n validateIdTokenIatMaxOffset(\r\n dataIdToken: any,\r\n maxOffsetAllowedInSeconds: number,\r\n disableIatOffsetValidation: boolean,\r\n configuration: OpenIdConfiguration\r\n ): boolean {\r\n if (disableIatOffsetValidation) {\r\n return true;\r\n }\r\n\r\n if (!Object.prototype.hasOwnProperty.call(dataIdToken, 'iat')) {\r\n return false;\r\n }\r\n\r\n const dateTimeIatIdToken = new Date(0); // The 0 here is the key, which sets the date to the epoch\r\n\r\n dateTimeIatIdToken.setUTCSeconds(dataIdToken.iat);\r\n maxOffsetAllowedInSeconds = maxOffsetAllowedInSeconds || 0;\r\n\r\n const nowInUtc = new Date(new Date().toUTCString());\r\n const diff = nowInUtc.valueOf() - dateTimeIatIdToken.valueOf();\r\n const maxOffsetAllowedInMilliseconds = maxOffsetAllowedInSeconds * 1000;\r\n\r\n this.loggerService.logDebug(\r\n configuration,\r\n `validate id token iat max offset ${diff} < ${maxOffsetAllowedInMilliseconds}`\r\n );\r\n\r\n if (diff > 0) {\r\n return diff < maxOffsetAllowedInMilliseconds;\r\n }\r\n\r\n return -diff < maxOffsetAllowedInMilliseconds;\r\n }\r\n\r\n // id_token C9: The value of the nonce Claim MUST be checked to verify that it is the same value as the one\r\n // that was sent in the Authentication Request.The Client SHOULD check the nonce value for replay attacks.\r\n // The precise method for detecting replay attacks is Client specific.\r\n\r\n // However the nonce claim SHOULD not be present for the refresh_token grant type\r\n // https://bitbucket.org/openid/connect/issues/1025/ambiguity-with-how-nonce-is-handled-on\r\n // The current spec is ambiguous and KeyCloak does send it.\r\n validateIdTokenNonce(\r\n dataIdToken: any,\r\n localNonce: any,\r\n ignoreNonceAfterRefresh: boolean,\r\n configuration: OpenIdConfiguration\r\n ): boolean {\r\n const isFromRefreshToken =\r\n (dataIdToken.nonce === undefined || ignoreNonceAfterRefresh) &&\r\n localNonce === TokenValidationService.refreshTokenNoncePlaceholder;\r\n\r\n if (!isFromRefreshToken && dataIdToken.nonce !== localNonce) {\r\n this.loggerService.logDebug(\r\n configuration,\r\n 'Validate_id_token_nonce failed, dataIdToken.nonce: ' +\r\n dataIdToken.nonce +\r\n ' local_nonce:' +\r\n localNonce\r\n );\r\n\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n // id_token C1: The Issuer Identifier for the OpenID Provider (which is typically obtained during Discovery)\r\n // MUST exactly match the value of the iss (issuer) Claim.\r\n validateIdTokenIss(\r\n dataIdToken: any,\r\n authWellKnownEndpointsIssuer: any,\r\n configuration: OpenIdConfiguration\r\n ): boolean {\r\n if (\r\n (dataIdToken.iss as string) !== (authWellKnownEndpointsIssuer as string)\r\n ) {\r\n this.loggerService.logDebug(\r\n configuration,\r\n 'Validate_id_token_iss failed, dataIdToken.iss: ' +\r\n dataIdToken.iss +\r\n ' authWellKnownEndpoints issuer:' +\r\n authWellKnownEndpointsIssuer\r\n );\r\n\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n // id_token C2: The Client MUST validate that the aud (audience) Claim contains its client_id value registered at the Issuer identified\r\n // by the iss (issuer) Claim as an audience.\r\n // The ID Token MUST be rejected if the ID Token does not list the Client as a valid audience, or if it contains additional audiences\r\n // not trusted by the Client.\r\n validateIdTokenAud(\r\n dataIdToken: any,\r\n aud: string | undefined,\r\n configuration: OpenIdConfiguration\r\n