@ascentgl/ads-identity 22.3.0 → 22.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -338,16 +338,16 @@ class PkceHelper {
|
|
|
338
338
|
static async buildLoginRedirectUrl(options, redirectPath) {
|
|
339
339
|
const verifier = PkceHelper.createVerifier();
|
|
340
340
|
const challenge = await PkceHelper.createChallenge(verifier);
|
|
341
|
-
|
|
341
|
+
localStorage.setItem("IDMS_PkceVerifier", verifier);
|
|
342
342
|
return (`${options.frontendUrl}/apps/${options.application}` +
|
|
343
343
|
`?redirect=true&redirect_path=${encodeURIComponent(redirectPath)}` +
|
|
344
344
|
`&code_challenge=${challenge}&code_challenge_method=S256`);
|
|
345
345
|
}
|
|
346
346
|
static readVerifier() {
|
|
347
|
-
return
|
|
347
|
+
return localStorage.getItem("IDMS_PkceVerifier");
|
|
348
348
|
}
|
|
349
349
|
static clearVerifier() {
|
|
350
|
-
|
|
350
|
+
localStorage.removeItem("IDMS_PkceVerifier");
|
|
351
351
|
}
|
|
352
352
|
static toBase64Url(bytes) {
|
|
353
353
|
let binary = '';
|
|
@@ -411,8 +411,11 @@ class IdentityService {
|
|
|
411
411
|
this.tokenService.clearTokens();
|
|
412
412
|
}
|
|
413
413
|
redeemCode(code) {
|
|
414
|
-
const codeVerifier = PkceHelper.readVerifier()
|
|
414
|
+
const codeVerifier = PkceHelper.readVerifier();
|
|
415
415
|
PkceHelper.clearVerifier();
|
|
416
|
+
if (!codeVerifier) {
|
|
417
|
+
return throwError(() => new InvalidTokenError('Missing PKCE verifier; cannot redeem code'));
|
|
418
|
+
}
|
|
416
419
|
return this.httpClient
|
|
417
420
|
.post(`${this.options.backendUrl}/api/v${this.options.apiVersion ?? 1}/redeem-code`, {
|
|
418
421
|
code,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ascentgl-ads-identity.mjs","sources":["../../../../libs/ads-identity/src/lib/helpers/log.helper.ts","../../../../libs/ads-identity/src/lib/helpers/error.helper.ts","../../../../libs/ads-identity/src/lib/helpers/token.helper.ts","../../../../libs/ads-identity/src/lib/types/internal-consts.ts","../../../../libs/ads-identity/src/lib/services/jwks.service.ts","../../../../libs/ads-identity/src/lib/services/token.service.ts","../../../../libs/ads-identity/src/lib/helpers/pkce.helper.ts","../../../../libs/ads-identity/src/lib/services/identity.service.ts","../../../../libs/ads-identity/src/lib/guards/auth.guard.ts","../../../../libs/ads-identity/src/lib/guards/auth-callback.guard.ts","../../../../libs/ads-identity/src/lib/helpers/request.helper.ts","../../../../libs/ads-identity/src/lib/interceptors/request.interceptor.ts","../../../../libs/ads-identity/src/lib/interceptors/response.interceptor.ts","../../../../libs/ads-identity/src/lib/providers/identity.provider.ts"],"sourcesContent":["import { IdentityOptions } from '../types/internal-types';\r\n\r\nexport class LogHelper {\r\n static options?: IdentityOptions;\r\n\r\n private static readonly prefix = 'ADS-IDENTITY';\r\n\r\n static log(...args: unknown[]) {\r\n if (!this.options?.debugMode) return false;\r\n\r\n console.group(this.prefix, 'TOKEN UPDATE');\r\n\r\n console.log(...args);\r\n\r\n console.groupEnd();\r\n\r\n return true;\r\n }\r\n\r\n static error(...args: unknown[]) {\r\n if (!this.options?.debugMode) return false;\r\n\r\n console.group(this.prefix, 'EXCEPTION');\r\n\r\n console.error(...args);\r\n\r\n console.groupEnd();\r\n\r\n return true;\r\n }\r\n}\r\n","import { HttpErrorResponse } from '@angular/common/http';\r\nimport { GenericCollection } from '../types/internal-types';\r\n\r\nexport class ErrorHelper {\r\n static extractMessage(error: unknown): string {\r\n if (typeof error === 'string' && error) {\r\n return error;\r\n }\r\n\r\n let errorMessage: unknown;\r\n\r\n if (error instanceof HttpErrorResponse) {\r\n errorMessage = error.error?.message ?? error.message;\r\n }\r\n\r\n if (!errorMessage && typeof error === 'object' && typeof (<GenericCollection>error)['message'] === 'string') {\r\n errorMessage = (<GenericCollection>error)['message'];\r\n }\r\n\r\n return errorMessage && typeof errorMessage === 'string' ? errorMessage : 'Unknown server error';\r\n }\r\n}\r\n","import { InvalidTokenError, jwtDecode, JwtHeader } from 'jwt-decode';\r\nimport { GenericCollection, IdentityJwtClaim, AccessTokenPayload, RefreshTokenPayload } from '../types/internal-types';\r\nimport { LogHelper } from './log.helper';\r\nimport { ErrorHelper } from './error.helper';\r\n\r\nexport class TokenHelper {\r\n static getPayload<T extends AccessTokenPayload | RefreshTokenPayload>(\r\n token: string,\r\n verifyClaims: GenericCollection = {},\r\n threshold = 0,\r\n ): T {\r\n const payload: T = jwtDecode(token);\r\n\r\n /**\r\n * throw error if the token is expired\r\n */\r\n if (this.isExpired(payload, 'exp', threshold)) {\r\n throw new InvalidTokenError('Token expired');\r\n }\r\n\r\n /**\r\n * loop through claims to verify and make sure the payload matches their values\r\n */\r\n Object.keys(verifyClaims).forEach((claim) => {\r\n const tokenClaimValue = payload[claim];\r\n const requestedClaimValue = verifyClaims[claim];\r\n\r\n if (!this.isClaimValid(tokenClaimValue, requestedClaimValue)) {\r\n throw new InvalidTokenError(\r\n `Invalid \"${claim}\" claim value \"${tokenClaimValue}\" provided in token. Required value is \"${requestedClaimValue}\"`,\r\n );\r\n }\r\n });\r\n\r\n return payload;\r\n }\r\n\r\n /**\r\n * decoded JOSE header (alg/kid) — used to detect asymmetrically signed\r\n * (RS256) tokens that must be verified against the IDMS JWKS. Throws\r\n * InvalidTokenError on malformed input, like every other decoding here.\r\n */\r\n static getHeader(token: string): JwtHeader {\r\n return jwtDecode<JwtHeader>(token, { header: true });\r\n }\r\n\r\n private static isExpired<T extends AccessTokenPayload | RefreshTokenPayload>(\r\n token: T,\r\n claim: IdentityJwtClaim = 'exp',\r\n threshold = 0,\r\n ): boolean {\r\n const throwInvalidColumnError = (column: string): true => {\r\n throw new InvalidTokenError(`Column ${column} does not contain a valid number`);\r\n };\r\n\r\n try {\r\n /**\r\n * get value from the column\r\n */\r\n let timestamp: unknown = token[claim];\r\n\r\n /**\r\n * if values is a number - compare it against the current date\r\n */\r\n if (typeof timestamp === 'number') {\r\n /**\r\n * if a threshold is set - extract it from the timestamp\r\n * NOTE: a threshold allows considering the timestamp expired earlier;\r\n * this allows to make sure the token does not expire while being transferred to backend\r\n */\r\n if (threshold > 0) {\r\n timestamp -= threshold;\r\n }\r\n\r\n return !!timestamp && timestamp * 1000 < new Date().getTime();\r\n }\r\n\r\n return throwInvalidColumnError(claim.toString());\r\n } catch (error: unknown) {\r\n LogHelper.error(new InvalidTokenError(ErrorHelper.extractMessage(error)));\r\n\r\n return true;\r\n }\r\n }\r\n\r\n private static isClaimValid(tokenClaim: unknown, valueToVerify: unknown) {\r\n /**\r\n * if any of the values is an array - apply special logic;\r\n * otherwise do strict comparison\r\n */\r\n if (tokenClaim instanceof Array || valueToVerify instanceof Array) {\r\n /**\r\n * if both claims are arrays - make sure they intersect\r\n */\r\n if (tokenClaim instanceof Array && valueToVerify instanceof Array) {\r\n return tokenClaim.filter((value) => valueToVerify.includes(value)).length > 0;\r\n }\r\n\r\n /**\r\n * if the first claim is an array and the second is a string -\r\n * check if the second is within the first\r\n */\r\n if (tokenClaim instanceof Array && typeof valueToVerify === 'string') {\r\n return tokenClaim.includes(valueToVerify);\r\n }\r\n\r\n /**\r\n * if the second claim is an array and the first is a string -\r\n * check if the first is within the second\r\n */\r\n if (valueToVerify instanceof Array && typeof tokenClaim === 'string') {\r\n return valueToVerify.includes(tokenClaim);\r\n }\r\n\r\n return false;\r\n }\r\n\r\n return tokenClaim === valueToVerify;\r\n }\r\n}\r\n","import { InjectionToken } from '@angular/core';\r\nimport { IdentityOptions } from './internal-types';\r\n\r\nexport const IDENTITY_OPTIONS = new InjectionToken<IdentityOptions>('IDENTITY_OPTIONS');\r\n\r\n/**\r\n * RSASSA-PKCS1-v1_5 with SHA-256 — the one algorithm IDMS signs RS256 tokens with\r\n */\r\nexport const RS256_ALGORITHM = { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };\r\n","import { inject, Service, signal } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { catchError, defer, from, map, Observable, of, share, switchMap } from 'rxjs';\r\nimport { InvalidTokenError } from 'jwt-decode';\r\nimport { IDENTITY_OPTIONS, RS256_ALGORITHM } from '../types/internal-consts';\r\nimport { Jwks, Nullable } from '../types/internal-types';\r\nimport { TokenHelper } from '../helpers/token.helper';\r\nimport { LogHelper } from '../helpers/log.helper';\r\n\r\n/**\r\n * Verifies RS256-signed IDMS ACCESS tokens against the public keys published\r\n * at {backendUrl}/api/.well-known/jwks.json (Web Crypto, no dependencies).\r\n *\r\n * ARCHITECTURE INVARIANT: only the ACCESS token can be RS256-signed. Refresh\r\n * tokens are ALWAYS HS256 by IDMS design and are never routed through this\r\n * service — their handling is byte-for-byte the pre-JWKS legacy behavior.\r\n *\r\n * The key cache lives in memory only — it dies with the page (by design) and\r\n * is eagerly replaced on every token acquisition (\"until a new access key is\r\n * obtained\"). HS256 tokens cannot be verified client-side and bypass\r\n * everything here.\r\n */\r\n@Service()\r\nexport class JwksService {\r\n private readonly httpClient = inject(HttpClient);\r\n private readonly options = inject(IDENTITY_OPTIONS);\r\n\r\n /** in-memory key cache — signal state, replaced wholesale on every fetch */\r\n private readonly keys = signal<Nullable<Jwks['keys']>>(null);\r\n\r\n /**\r\n * concurrent subscribers join ONE in-flight request (`share`), and the\r\n * connection resets on completion — so the next acquisition fetches anew.\r\n * NOT shareReplay: replaying a completed fetch's body is exactly the stale\r\n * key hazard. The cache-busted channel is a separate stream — a kid-rotation\r\n * retry must never piggyback on an in-flight plain fetch (its body may be\r\n * stale and would false-reject a legitimately rotated key).\r\n */\r\n private readonly keysFetch = defer(() => this.fetchKeys(false)).pipe(share());\r\n private readonly freshKeysFetch = defer(() => this.fetchKeys(true)).pipe(share());\r\n\r\n /**\r\n * acquisition-time check (redeem-code / legacy callback / refresh) for the\r\n * ACCESS token: eagerly refresh the JWKS, then verify the token BEFORE it\r\n * is stored. Errors with InvalidTokenError on a bad signature or unknown\r\n * kid.\r\n *\r\n * Emits SYNCHRONOUSLY for an HS256 token — legacy flows must keep their\r\n * exact timing (and fire no JWKS request at all). Resolves silently when\r\n * the JWKS endpoint is unavailable (unavailability lets the token pass;\r\n * an IDMS blip must not lock users out — mismatches still reject whenever\r\n * keys ARE available).\r\n */\r\n verifyNewToken(token: string): Observable<void> {\r\n /**\r\n * defer so malformed input (getHeader throws) surfaces as an Observable\r\n * error instead of a synchronous throw out of the call site — while the\r\n * HS256 fast path still emits synchronously on subscription\r\n */\r\n return defer(() => {\r\n if (TokenHelper.getHeader(token).alg !== 'RS256') {\r\n return of(undefined);\r\n }\r\n\r\n return this.loadKeys().pipe(switchMap(() => this.assertTokenValid(token)));\r\n });\r\n }\r\n\r\n /**\r\n * read-path check for a localStorage value that is not the current page's\r\n * verified copy (cold reload / cross-tab rotation / tampering). Lazily\r\n * fetches the JWKS when the cache is empty. Emits false ONLY on a definite\r\n * mismatch; unavailability lets the token pass (never locks users out).\r\n */\r\n verifyExistingToken(token: string): Observable<boolean> {\r\n return defer(() => {\r\n if (TokenHelper.getHeader(token).alg !== 'RS256') {\r\n return of(true);\r\n }\r\n\r\n return (this.keys() ? of(true) : this.loadKeys()).pipe(switchMap(() => this.verifyToken(token)));\r\n });\r\n }\r\n\r\n /**\r\n * acquisition gate: turns a failed check into a stream error, so the caller\r\n * can never store a token by forgetting to inspect a boolean\r\n */\r\n private assertTokenValid(token: string): Observable<void> {\r\n return this.verifyToken(token).pipe(\r\n map((valid) => {\r\n if (!valid) {\r\n throw new InvalidTokenError('Token signature verification failed against the IDMS JWKS');\r\n }\r\n }),\r\n );\r\n }\r\n\r\n private verifyToken(token: string): Observable<boolean> {\r\n /**\r\n * keys unavailable (endpoint unreachable and nothing cached) — let the\r\n * token pass rather than lock users out\r\n */\r\n if (!this.keys()) {\r\n return of(true);\r\n }\r\n\r\n const kid = TokenHelper.getHeader(token).kid;\r\n const jwk = this.findKey(kid);\r\n\r\n return jwk ? this.verifySignature(token, jwk) : this.retryWithFreshKeys(token, kid);\r\n }\r\n\r\n /**\r\n * unknown kid against a possibly stale cache: the signing key may have\r\n * rotated since we fetched — force ONE fresh (cache-busted) fetch before\r\n * rejecting. A failed re-fetch cannot distinguish rotation from outage,\r\n * so it also lets the token pass.\r\n */\r\n private retryWithFreshKeys(token: string, kid?: string): Observable<boolean> {\r\n return this.loadKeys(true).pipe(\r\n switchMap((loaded) => {\r\n if (!loaded) {\r\n return of(true);\r\n }\r\n\r\n const rotatedKey = this.findKey(kid);\r\n\r\n return rotatedKey ? this.verifySignature(token, rotatedKey) : of(false);\r\n }),\r\n );\r\n }\r\n\r\n private verifySignature(token: string, jwk: JsonWebKey): Observable<boolean> {\r\n const [header, payload, signature] = token.split('.');\r\n\r\n return defer(() => from(crypto.subtle.importKey('jwk', jwk, RS256_ALGORITHM, false, ['verify']))).pipe(\r\n switchMap((key) =>\r\n from(\r\n crypto.subtle.verify(\r\n RS256_ALGORITHM,\r\n key,\r\n JwksService.fromBase64Url(signature),\r\n new TextEncoder().encode(`${header}.${payload}`),\r\n ),\r\n ),\r\n ),\r\n catchError((error: unknown) => {\r\n LogHelper.error('JWKS verification errored — rejecting token', error);\r\n\r\n return of(false);\r\n }),\r\n );\r\n }\r\n\r\n private loadKeys(fresh = false): Observable<boolean> {\r\n return fresh ? this.freshKeysFetch : this.keysFetch;\r\n }\r\n\r\n private fetchKeys(fresh: boolean): Observable<boolean> {\r\n const url = `${this.options.backendUrl}/api/.well-known/jwks.json`;\r\n\r\n /**\r\n * `fresh` busts the browser HTTP cache (the endpoint serves max-age=3600)\r\n * for the kid-rotation retry — a plain refetching would just replay the\r\n * cached body\r\n */\r\n return this.httpClient.get<Jwks>(fresh ? `${url}?fresh=${Date.now()}` : url).pipe(\r\n map((jwks) => {\r\n this.keys.set(jwks.keys);\r\n\r\n return true;\r\n }),\r\n catchError((error: unknown) => {\r\n LogHelper.error('JWKS endpoint unavailable — failing open', error);\r\n\r\n return of(false);\r\n }),\r\n );\r\n }\r\n\r\n private findKey(kid?: string): Nullable<JsonWebKey> {\r\n return this.keys()?.find((key) => key.kid === kid) ?? null;\r\n }\r\n\r\n /**\r\n * returns Uint8Array<ArrayBuffer> (not the bare-Uint8Array default of\r\n * ArrayBufferLike) — Web Crypto's BufferSource rejects views that could be\r\n * backed by a SharedArrayBuffer\r\n */\r\n private static fromBase64Url(value: string): Uint8Array<ArrayBuffer> {\r\n const binary = atob(value.replace(/-/g, '+').replace(/_/g, '/'));\r\n\r\n return Uint8Array.from(binary, (char) => char.charCodeAt(0));\r\n }\r\n}\r\n","import { computed, inject, Injectable, signal } from '@angular/core';\r\nimport { catchError, map, Observable, of, shareReplay, switchMap } from 'rxjs';\r\nimport { IdentityToken, Nullable } from '../types/internal-types';\r\nimport { AccessToken, RefreshToken } from '../types/global-types';\r\nimport { TokenHelper } from '../helpers/token.helper';\r\nimport { InvalidTokenError } from 'jwt-decode';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { TokenKey } from '../types/internal-enums';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { JwksService } from './jwks.service';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class TokenService {\r\n /**\r\n * NOTE: we expose access and refresh tokens as computed signals so that they can be\r\n * used in \"IdentityService\" to allow library users reactive readonly access to tokens,\r\n * since \"IdentityService\" is the only \"public\" service in the library\r\n */\r\n readonlyAccessToken = computed(() => this.accessToken());\r\n readonlyRefreshToken = computed(() => this.refreshToken());\r\n\r\n private readonly accessToken = signal<Nullable<AccessToken>>(null);\r\n private readonly refreshToken = signal<Nullable<RefreshToken>>(null);\r\n\r\n private readonly options = inject(IDENTITY_OPTIONS);\r\n private readonly jwksService = inject(JwksService);\r\n\r\n /**\r\n * FAIL-CLOSED read gate for the ACCESS token: the token string this page\r\n * has verified (or adopted). A localStorage value that differs is NEVER\r\n * exposed until a background JWKS check adopts it (cold reload / cross-tab\r\n * rotation) or clears everything (tampering). HS256 access tokens bypass\r\n * the gate — they cannot be verified client-side by design.\r\n *\r\n * ARCHITECTURE INVARIANT: refresh tokens are ALWAYS HS256 by IDMS design,\r\n * so only the access token is ever gated/verified; the refresh path is\r\n * byte-for-byte the pre-JWKS legacy behavior.\r\n */\r\n private verifiedAccessToken: Nullable<string> = null;\r\n\r\n /** the single in-flight background verification (access token only) */\r\n private pendingVerification: Nullable<{ token: string; done: Observable<void> }> = null;\r\n\r\n private issuers: string[] = [];\r\n\r\n setAccessToken(token: unknown) {\r\n return this.updateAccessTokenSignal<AccessToken>(this.setToken<AccessToken>(TokenKey.accessToken, token));\r\n }\r\n\r\n getAccessToken() {\r\n return this.updateAccessTokenSignal(this.getToken(TokenKey.accessToken));\r\n }\r\n\r\n setRefreshToken(token: unknown) {\r\n return this.updateRefreshTokenSignal<RefreshToken>(this.setToken(TokenKey.refreshToken, token));\r\n }\r\n\r\n getRefreshToken() {\r\n return this.updateRefreshTokenSignal(this.getToken(TokenKey.refreshToken));\r\n }\r\n\r\n /**\r\n * emits+completes once background verification is quiescent; never errors.\r\n * IdentityService.authenticate() composes this so guarded navigation and\r\n * Bearer attachment wait for the verdict instead of failing on the\r\n * fail-closed null read. Emits synchronously when nothing is pending.\r\n *\r\n * Re-checks after each settled verdict: a NEWER token may have superseded\r\n * the in-flight check while we waited (cross-tab rotation mid-fetch) —\r\n * resolving on the stale verdict alone would send authenticate() into a\r\n * needless token rotation.\r\n */\r\n whenVerified(): Observable<void> {\r\n const pending = this.pendingVerification;\r\n\r\n if (!pending) {\r\n return of(undefined);\r\n }\r\n\r\n return pending.done.pipe(\r\n /**\r\n * recurse ONLY when a different check replaced the slot — the settled\r\n * verdict may replay before our own finalizing clears it, and recursing\r\n * into the same entry would loop forever\r\n */\r\n switchMap(() => (this.pendingVerification === pending ? of(undefined) : this.whenVerified())),\r\n );\r\n }\r\n\r\n /**\r\n * whether background access-token verification is in flight RIGHT NOW.\r\n * whenVerified() only covers checks that existed while it was waiting — a\r\n * read performed AFTER it settles may itself discover a newer unverified\r\n * token and start a fresh check; authenticate() uses this to wait for that\r\n * verdict too instead of treating the fail-closed null read as \"no token\".\r\n */\r\n hasPendingVerification(): boolean {\r\n return this.pendingVerification !== null;\r\n }\r\n\r\n clearTokens() {\r\n localStorage.removeItem(TokenKey.accessToken);\r\n localStorage.removeItem(TokenKey.refreshToken);\r\n\r\n this.updateAccessTokenSignal(null);\r\n this.updateRefreshTokenSignal(null);\r\n\r\n this.verifiedAccessToken = null;\r\n }\r\n\r\n private updateAccessTokenSignal<T extends Nullable<AccessToken>>(newToken: Nullable<AccessToken>): T {\r\n if (this.accessToken()?.token !== newToken?.token) {\r\n this.accessToken.set(newToken);\r\n }\r\n\r\n return <T>this.accessToken();\r\n }\r\n\r\n private updateRefreshTokenSignal<T extends Nullable<RefreshToken>>(newToken: Nullable<RefreshToken>): T {\r\n if (this.refreshToken()?.token !== newToken?.token) {\r\n this.refreshToken.set(newToken);\r\n }\r\n\r\n return <T>this.refreshToken();\r\n }\r\n\r\n private setToken<T extends IdentityToken>(key: TokenKey, token: unknown): T {\r\n /**\r\n * make sure the provided token is at least a string\r\n */\r\n if (typeof token !== 'string') {\r\n throw new InvalidTokenError(`Provided ${key} value is not a string`);\r\n }\r\n\r\n /**\r\n * get identity token\r\n */\r\n const identityToken = this.wrapToken<T>(token);\r\n\r\n /**\r\n * if provided - save it to local storage\r\n */\r\n if (identityToken) {\r\n localStorage.setItem(key, token);\r\n\r\n /**\r\n * acquisition points verify the RS256 access token BEFORE calling the\r\n * setter (JwksService.verifyNewToken) — record the stored string as\r\n * this page's verified copy so reads stay a sync string compare\r\n */\r\n if (key === TokenKey.accessToken) {\r\n this.verifiedAccessToken = token;\r\n }\r\n }\r\n\r\n LogHelper.log(key, identityToken);\r\n\r\n return identityToken;\r\n }\r\n\r\n private getToken<T extends IdentityToken>(key: TokenKey): Nullable<T> {\r\n /**\r\n * get token value from local storage or use null\r\n */\r\n const actualToken = localStorage.getItem(key) ?? null;\r\n\r\n if (typeof actualToken === 'string') {\r\n try {\r\n /**\r\n * FAIL CLOSED (access token only — refresh tokens are ALWAYS HS256\r\n * by IDMS architecture and take the legacy path below): an RS256\r\n * access token that is not this page's verified copy is not exposed —\r\n * verify it in the background and report \"no token\" meanwhile\r\n * (authenticate() awaits the verdict via whenVerified())\r\n */\r\n if (key === TokenKey.accessToken && !this.isVerified(actualToken)) {\r\n this.verifyInBackground(actualToken);\r\n\r\n return null;\r\n }\r\n\r\n return this.wrapToken<T>(actualToken);\r\n } catch (error) {\r\n LogHelper.error(error);\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n private isVerified(token: string): boolean {\r\n /**\r\n * only asymmetric (RS256) tokens are verifiable client-side; anything\r\n * else behaves exactly as before this feature existed\r\n */\r\n if (TokenHelper.getHeader(token).alg !== 'RS256') {\r\n return true;\r\n }\r\n\r\n return this.verifiedAccessToken === token;\r\n }\r\n\r\n private verifyInBackground(token: string) {\r\n /**\r\n * one in-flight check per token value; repeated sync reads while the\r\n * verdict is pending must not stack up requests\r\n */\r\n if (this.pendingVerification?.token === token) {\r\n return;\r\n }\r\n\r\n const done = this.jwksService.verifyExistingToken(token).pipe(\r\n /**\r\n * an ERROR from the verification (e.g., malformed token) is treated\r\n * exactly like failed verification — whenVerified() must never error\r\n */\r\n catchError((error: unknown) => {\r\n LogHelper.error(error);\r\n\r\n return of(false);\r\n }),\r\n map((valid) => {\r\n /**\r\n * Clear the slot BEFORE applying the verdict: authenticate() re-reads\r\n * synchronously as the verdict emits, and a still-set slot makes\r\n * hasPendingVerification() loop forever on a token that verifies but\r\n * can't be read (wrong iss/sub). A newer token re-registers after this.\r\n */\r\n if (this.pendingVerification?.token === token) {\r\n this.pendingVerification = null;\r\n }\r\n\r\n return this.applyVerdict(token, valid);\r\n }),\r\n /**\r\n * late whenVerified() subscribers must still observe the settled verdict\r\n */\r\n shareReplay(1),\r\n );\r\n\r\n this.pendingVerification = { token, done };\r\n\r\n /**\r\n * kick the background check off immediately — reads are sync and never\r\n * subscribe themselves\r\n */\r\n done.subscribe();\r\n }\r\n\r\n private applyVerdict(token: string, valid: boolean): void {\r\n /**\r\n * the stored value moved on while we verified (another tab rotated it, or\r\n * clearTokens ran) — this verdict is about a token nobody holds anymore\r\n */\r\n if (localStorage.getItem(TokenKey.accessToken) !== token) {\r\n return;\r\n }\r\n\r\n if (!valid) {\r\n /**\r\n * definite mismatch = tampering; drop everything and force a re-login\r\n * on the next guarded navigation\r\n */\r\n LogHelper.error(new InvalidTokenError('Stored access token failed JWKS signature verification'));\r\n\r\n return this.clearTokens();\r\n }\r\n\r\n /**\r\n * verify-then-adopt: a legit cold reload or another tab rotated the\r\n * token — adopt and re-read so the signal refreshes for reactive\r\n * consumers\r\n */\r\n this.verifiedAccessToken = token;\r\n\r\n this.getAccessToken();\r\n }\r\n\r\n private wrapToken<T extends IdentityToken>(token: string): T {\r\n /**\r\n * parse a token and get its payload\r\n * NOTE: errors will be thrown if the token is expired or has invalid claims\r\n */\r\n const payload = TokenHelper.getPayload(\r\n token,\r\n {\r\n iss: this.getIssuers(),\r\n sub: this.options.application,\r\n },\r\n 60,\r\n );\r\n\r\n /**\r\n * return identity token object\r\n */\r\n return <T>{ token, payload: payload };\r\n }\r\n\r\n private getIssuers(): string[] {\r\n /**\r\n * if we already have issuers - ise them\r\n */\r\n if (this.issuers.length) {\r\n return this.issuers;\r\n }\r\n\r\n /**\r\n * get issuer value from the options\r\n */\r\n const issuer = this.options.serviceIssuer ?? this.options.backendUrl;\r\n\r\n this.issuers = [issuer];\r\n\r\n /**\r\n * make sure we have both variants (with and without \"/api\" suffix) as issuers\r\n * todo \"/api\" suffix verification must be removed when \"/api\" suffix will be removed from the \"issuer\" in IDMS\r\n */\r\n if (issuer.endsWith('/api')) {\r\n this.issuers.push(issuer.substring(0, issuer.lastIndexOf('/api')));\r\n } else {\r\n this.issuers.push(`${issuer}/api`);\r\n }\r\n\r\n return this.issuers;\r\n }\r\n}\r\n","import { TokenKey } from '../types/internal-enums';\r\n\r\n/**\r\n * PKCE (RFC 7636, S256) for the code-flow app launch.\r\n *\r\n * The `code_verifier` is a secret kept in `sessionStorage` across the\r\n * app → IDMS → app round trip (same tab). Only the `code_challenge` (its SHA-256\r\n * hash) travels on the outbound redirect URL. IDMS bakes the challenge into the\r\n * one-time code and verifies the presented verifier at `POST /redeem-code`.\r\n */\r\nexport class PkceHelper {\r\n /**\r\n * 43-char base64url verifier from 32 CSPRNG bytes — inside RFC 7636's 43–128\r\n * range, unreserved charset (base64url ⊂ unreserved).\r\n */\r\n static createVerifier(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n return PkceHelper.toBase64Url(bytes);\r\n }\r\n\r\n /** `BASE64URL(SHA256(verifier))` — the S256 challenge (RFC 7636 §4.2). */\r\n static async createChallenge(verifier: string): Promise<string> {\r\n const digest = await crypto.subtle.digest(\r\n 'SHA-256',\r\n new TextEncoder().encode(verifier),\r\n );\r\n return PkceHelper.toBase64Url(new Uint8Array(digest));\r\n }\r\n\r\n /**\r\n * Generate a verifier, stash it for the pending `/redeem-code`, and build the\r\n * IDMS login redirect URL carrying the S256 challenge. Returned (not applied)\r\n * so the caller assigns `window.location.href` — keeps this unit testable\r\n * without triggering navigation.\r\n */\r\n static async buildLoginRedirectUrl(\r\n options: { frontendUrl: string; application: string },\r\n redirectPath: string,\r\n ): Promise<string> {\r\n const verifier = PkceHelper.createVerifier();\r\n const challenge = await PkceHelper.createChallenge(verifier);\r\n\r\n sessionStorage.setItem(TokenKey.pkceVerifier, verifier);\r\n\r\n return (\r\n `${options.frontendUrl}/apps/${options.application}` +\r\n `?redirect=true&redirect_path=${encodeURIComponent(redirectPath)}` +\r\n `&code_challenge=${challenge}&code_challenge_method=S256`\r\n );\r\n }\r\n\r\n /** The verifier stashed for the pending redemption (or `null`). */\r\n static readVerifier(): string | null {\r\n return sessionStorage.getItem(TokenKey.pkceVerifier);\r\n }\r\n\r\n static clearVerifier(): void {\r\n sessionStorage.removeItem(TokenKey.pkceVerifier);\r\n }\r\n\r\n private static toBase64Url(bytes: Uint8Array): string {\r\n let binary = '';\r\n for (const byte of bytes) {\r\n binary += String.fromCharCode(byte);\r\n }\r\n return btoa(binary)\r\n .replace(/\\+/g, '-')\r\n .replace(/\\//g, '_')\r\n .replace(/=+$/, '');\r\n }\r\n}\r\n","import { computed, inject, Injectable } from '@angular/core';\r\nimport {\r\n catchError,\r\n finalize,\r\n map,\r\n Observable,\r\n of,\r\n shareReplay,\r\n switchMap,\r\n throwError,\r\n} from 'rxjs';\r\nimport { TokenService } from './token.service';\r\nimport { JwksService } from './jwks.service';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { Nullable, RefreshTokenResponse } from '../types/internal-types';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { PkceHelper } from '../helpers/pkce.helper';\r\nimport { AccessToken } from '../types/global-types';\r\nimport { InvalidTokenError } from 'jwt-decode';\r\nimport { ErrorHelper } from '../helpers/error.helper';\r\nimport { IdentityServiceInterface } from '../interfaces/identity-service.interface';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class IdentityService implements IdentityServiceInterface {\r\n /**\r\n * NOTE: we expose access and refresh tokens as computed signals to allow\r\n * library users reactive readonly access to tokens, since \"IdentityService\"\r\n * is the only \"public\" service in the library\r\n */\r\n readonly accessToken = computed(() => this.tokenService.readonlyAccessToken());\r\n readonly refreshToken = computed(() => this.tokenService.readonlyRefreshToken());\r\n\r\n private refreshInProgress: Nullable<Observable<AccessToken>> = null;\r\n\r\n private readonly tokenService = inject(TokenService);\r\n private readonly jwksService = inject(JwksService);\r\n private readonly httpClient = inject(HttpClient);\r\n private readonly options = inject(IDENTITY_OPTIONS);\r\n\r\n isAuthenticated() {\r\n return !!this.tokenService.getAccessToken();\r\n }\r\n\r\n authenticate(): Observable<AccessToken> {\r\n /**\r\n * get access token (the read also starts the background JWKS check when\r\n * the stored RS256 token is not verified yet)\r\n */\r\n const accessToken = this.tokenService.getAccessToken();\r\n\r\n /**\r\n * if it is available - return it (synchronous fast path — unchanged for\r\n * verified/HS256 tokens)\r\n */\r\n if (accessToken) {\r\n return of(accessToken);\r\n }\r\n\r\n /**\r\n * the access token read may be null because a background JWKS\r\n * verification is still in flight (cold reload / cross-tab rotation) —\r\n * ALWAYS wait for that verdict before deciding, and only then fall back\r\n * to the refresh token. Deciding on the refresh token early would turn\r\n * every cold reload of a valid RS256 session into a needless token\r\n * rotation (refresh tokens are always HS256, so they read as available\r\n * while the access verdict is still pending). With no verification\r\n * pending, whenVerified() emits synchronously — legacy timing unchanged.\r\n */\r\n return this.decideWhenQuiescent();\r\n }\r\n\r\n /**\r\n * wait for any in-flight background verification, then decide from FRESH\r\n * reads. Recurses when the deciding re-read itself discovers a newer\r\n * unverified token (cross-tab rotation landing between a settled verdict\r\n * and the re-read — a check whenVerified() could not have covered because\r\n * it did not exist yet); otherwise that read's fail-closed null would be\r\n * mistaken for \"no token\" and trigger a needless rotation. Each recursion\r\n * consumes a real async verdict, so this terminates as soon as rotations\r\n * stop. Legacy HS256 reads never start a check — for them everything here\r\n * stays synchronous and same-tick.\r\n */\r\n private decideWhenQuiescent(): Observable<AccessToken> {\r\n return this.tokenService.whenVerified().pipe(\r\n switchMap(() => {\r\n const verifiedAccessToken = this.tokenService.getAccessToken();\r\n\r\n if (verifiedAccessToken) {\r\n return of(verifiedAccessToken);\r\n }\r\n\r\n if (this.tokenService.hasPendingVerification()) {\r\n return this.decideWhenQuiescent();\r\n }\r\n\r\n if (this.tokenService.getRefreshToken()) {\r\n return this.refreshTokens();\r\n }\r\n\r\n /**\r\n * throw error if no tokens are available\r\n */\r\n return throwError(() => new InvalidTokenError('No valid tokens found'));\r\n }),\r\n );\r\n }\r\n\r\n refreshTokens(): Observable<AccessToken> {\r\n if (this.refreshInProgress) return this.refreshInProgress;\r\n\r\n this.refreshInProgress = this.performRefresh().pipe(\r\n catchError((error: unknown) => {\r\n this.refreshInProgress = null;\r\n return throwError(() => error);\r\n }),\r\n finalize(() => {\r\n this.refreshInProgress = null;\r\n }),\r\n shareReplay(1),\r\n );\r\n\r\n return this.refreshInProgress;\r\n }\r\n\r\n clearTokens() {\r\n this.tokenService.clearTokens();\r\n }\r\n\r\n /**\r\n * exchange a one-time authorization code (delivered in the app callback by a\r\n * code-enabled IDMS app) for the SAME token pair the legacy tokens-in-URL\r\n * callback delivers. Storage is the caller's job (the auth-callback guard),\r\n * mirroring how the guard stores tokens today.\r\n *\r\n * NOTE: `redirect_uri` MUST equal this app's IDMS `loginUrl` — i.e., the\r\n * callback route we are currently on — so IDMS's bind-check on redemption\r\n * passes. We derive it from the current location.\r\n *\r\n * PKCE (RFC 7636): send the `code_verifier` stashed by the launch redirect\r\n * (PkceHelper); IDMS re-hashes it against the code's challenge. Cleared on\r\n * success — it is single-use like the code.\r\n */\r\n redeemCode(code: string): Observable<RefreshTokenResponse> {\r\n /**\r\n * the verifier is single-use — read it and drop it immediately, regardless\r\n * of the redeem outcome. The value is captured in the request body below, so\r\n * a failed/replayed attempt never leaves a spent verifier in sessionStorage.\r\n */\r\n const codeVerifier = PkceHelper.readVerifier() ?? '';\r\n PkceHelper.clearVerifier();\r\n\r\n return this.httpClient\r\n .post<RefreshTokenResponse>(\r\n `${this.options.backendUrl}/api/v${this.options.apiVersion ?? 1}/redeem-code`,\r\n {\r\n code,\r\n client_id: this.options.application,\r\n redirect_uri: `${window.location.origin}${window.location.pathname}`,\r\n code_verifier: codeVerifier,\r\n },\r\n )\r\n .pipe(\r\n switchMap((response) =>\r\n /**\r\n * verify the RS256 access token against a fresh JWKS BEFORE handing\r\n * the pair to the caller (the callback guard stores them); HS256\r\n * access tokens pass through synchronously untouched. The refresh\r\n * token is ALWAYS HS256 (IDMS architecture) and is never verified.\r\n */\r\n this.jwksService.verifyNewToken(response.access_token).pipe(map(() => response)),\r\n ),\r\n );\r\n }\r\n\r\n private performRefresh() {\r\n const refreshToken = this.tokenService.getRefreshToken();\r\n\r\n /**\r\n * throw error if the refresh token is not available\r\n */\r\n if (!refreshToken) {\r\n return throwError(() => new InvalidTokenError('No refresh token found'));\r\n }\r\n\r\n /**\r\n * make a request to Identity service to get new tokens\r\n */\r\n return this.httpClient\r\n .get<RefreshTokenResponse>(`${this.options.backendUrl}/api/v${this.options.apiVersion ?? 1}/refresh-token`, {\r\n headers: { Authorization: `Bearer ${refreshToken.token}` },\r\n })\r\n .pipe(\r\n catchError((error: unknown) => {\r\n /**\r\n * log error if it happens\r\n */\r\n LogHelper.error(\r\n new InvalidTokenError(\r\n `Failed to obtain tokens. Reason: ${ErrorHelper.extractMessage(error).toLowerCase()}`,\r\n ),\r\n );\r\n\r\n return throwError(() => error);\r\n }),\r\n switchMap((response) =>\r\n /**\r\n * \"new access key obtained\" — eagerly refresh the JWKS cache and\r\n * verify the RS256 access token BEFORE anything is stored (the\r\n * refresh token is ALWAYS HS256 and is never verified)\r\n */\r\n this.jwksService.verifyNewToken(response.access_token).pipe(map(() => response)),\r\n ),\r\n map((response) => {\r\n /**\r\n * set refresh token\r\n */\r\n this.tokenService.setRefreshToken(response.refresh_token);\r\n\r\n /**\r\n * set and return access token\r\n */\r\n return this.tokenService.setAccessToken(response.access_token);\r\n }),\r\n );\r\n }\r\n}\r\n","import { CanActivateFn } from '@angular/router';\r\nimport { inject } from '@angular/core';\r\nimport { IdentityService } from '../services/identity.service';\r\nimport { catchError, from, map } from 'rxjs';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { PkceHelper } from '../helpers/pkce.helper';\r\n\r\nexport const IDENTITY_AUTH_GUARD: CanActivateFn = (_route, state) => {\r\n const identityService = inject(IdentityService);\r\n const options = inject(IDENTITY_OPTIONS);\r\n\r\n /**\r\n * check if the user is authenticated;\r\n * if an error happened - redirect to IDMS url to re-login;\r\n * return true on success and false on error\r\n */\r\n return identityService.authenticate().pipe(\r\n catchError((error) => {\r\n LogHelper.error(error);\r\n\r\n /**\r\n * no session → re-login. PKCE: stash a code_verifier and redirect to IDMS\r\n * with the S256 code_challenge so the code IDMS mints are bound to this\r\n * client (verified back at POST /redeem-code).\r\n */\r\n return from(PkceHelper.buildLoginRedirectUrl(options, state.url)).pipe(\r\n map((url) => {\r\n window.location.href = url;\r\n\r\n return null;\r\n }),\r\n );\r\n }),\r\n map((accessToken) => !!accessToken),\r\n );\r\n};\r\n","import { CanActivateFn, Router } from '@angular/router';\r\nimport { inject } from '@angular/core';\r\nimport { catchError, from, map, of, switchMap } from 'rxjs';\r\nimport { TokenService } from '../services/token.service';\r\nimport { IdentityService } from '../services/identity.service';\r\nimport { JwksService } from '../services/jwks.service';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { ErrorHelper } from '../helpers/error.helper';\r\nimport { PkceHelper } from '../helpers/pkce.helper';\r\n\r\nexport const IDENTITY_AUTH_CALLBACK_GUARD: CanActivateFn = (route) => {\r\n const router = inject(Router);\r\n const tokenService = inject(TokenService);\r\n const identityService = inject(IdentityService);\r\n const jwksService = inject(JwksService);\r\n const options = inject(IDENTITY_OPTIONS);\r\n\r\n /**\r\n * display an error message on the page and return false to stop further\r\n * navigation; text (not HTML) because the message may embed attacker-controlled\r\n * JWT claim values from the callback query param (innerHTML would be XSS)\r\n */\r\n const denyWithError = (error: unknown) => {\r\n const routerOutlet = document.body.querySelector('router-outlet');\r\n\r\n if (routerOutlet) {\r\n routerOutlet.textContent = ErrorHelper.extractMessage(error);\r\n }\r\n\r\n LogHelper.error(error);\r\n\r\n return false;\r\n };\r\n\r\n const applyTokens = (accessToken: string, refreshToken: string) => {\r\n tokenService.setAccessToken(accessToken);\r\n\r\n tokenService.setRefreshToken(refreshToken);\r\n\r\n return router.navigateByUrl(route.queryParams['redirect_path'] || '/');\r\n };\r\n\r\n const code = route.queryParams['code'];\r\n\r\n /**\r\n * bare launch: IDMS had a session but was launched with no redirect_path, so\r\n * it minted no code and sent us here with `code=none`. Re-login *explicitly*\r\n * with a redirect_path so IDMS mints a real code. The redirect_path MUST be\r\n * non-empty, or IDMS returns `code=none` again (infinite loop) — a bare launch\r\n * has no deep-link target, so falls back to the app root, exactly as the token\r\n * path below does for navigation.\r\n */\r\n if (code === 'none') {\r\n // re-login WITH a redirect_path (loop guard) and, like the auth guard, a\r\n // fresh PKCE challenge so IDMS can mint a code bound to this client.\r\n return from(\r\n PkceHelper.buildLoginRedirectUrl(\r\n options,\r\n route.queryParams['redirect_path'] || '/',\r\n ),\r\n ).pipe(\r\n map((url) => {\r\n window.location.href = url;\r\n\r\n return false;\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * code-enabled app: exchange the one-time code for the same token pair the\r\n * legacy path receives, store it (as below), and navigate to redirect_path.\r\n */\r\n if (code) {\r\n return identityService.redeemCode(code).pipe(\r\n switchMap(response => applyTokens(response.access_token, response.refresh_token)),\r\n catchError((error: unknown) => of(denyWithError(error))),\r\n );\r\n }\r\n\r\n if (!route.queryParams['access_token'] || !route.queryParams['refresh_token']) {\r\n return denyWithError('No access or refresh token provided');\r\n }\r\n\r\n /**\r\n * legacy tokens-in-URL: verify the RS256 access token against a fresh JWKS\r\n * BEFORE the tokens are stored (an HS256 access token passes through\r\n * synchronously untouched; the refresh token is ALWAYS HS256 by IDMS\r\n * architecture and is never verified). setAccessToken/setRefreshToken still\r\n * decode+validate and throw on an expired/invalid token; both failure kinds\r\n * surface as the error page via catchError (the code branch above gets the\r\n * same treatment).\r\n */\r\n return jwksService.verifyNewToken(route.queryParams['access_token']).pipe(\r\n switchMap(() => applyTokens(route.queryParams['access_token'], route.queryParams['refresh_token'])),\r\n catchError((error: unknown) => of(denyWithError(error))),\r\n );\r\n};\r\n","import { HttpErrorResponse, HttpRequest } from '@angular/common/http';\r\nimport { throwError } from 'rxjs';\r\nimport { Injector } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { IdentityOptions } from '../types/internal-types';\r\nimport { AccessToken } from '../types/global-types';\r\nimport { IDENTITY_AUTH_GUARD } from '../guards/auth.guard';\r\n\r\nexport class RequestHelper {\r\n static options?: IdentityOptions;\r\n\r\n static isIdentityEndpointRequest(request: HttpRequest<unknown>): boolean {\r\n return (\r\n (!!this.options?.backendUrl && request.url.startsWith(this.options?.backendUrl)) ||\r\n (!!this.options?.frontendUrl && request.url.startsWith(this.options?.frontendUrl))\r\n );\r\n }\r\n\r\n static isAuthorizedRequest(request: HttpRequest<unknown>, router: Router): boolean {\r\n return this.isRouteGuarded(router) && (!this.options?.requestFilter || this.options.requestFilter(request));\r\n }\r\n\r\n /**\r\n * a request is authorized only when the active route (or one of its\r\n * ancestors) is protected by IDENTITY_AUTH_GUARD, so unguarded pages never\r\n * trigger authentication\r\n */\r\n private static isRouteGuarded(router: Router): boolean {\r\n let route = router.routerState.snapshot.root.firstChild;\r\n\r\n while (route) {\r\n const guards = [...(route.routeConfig?.canActivate ?? []), ...(route.routeConfig?.canActivateChild ?? [])];\r\n\r\n if (guards.includes(IDENTITY_AUTH_GUARD)) {\r\n return true;\r\n }\r\n\r\n // ponytail: primary outlet only; recurse children if named-outlet guards ever matter\r\n route = route.firstChild;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n static isAuthorizationError(error: unknown): boolean {\r\n return error instanceof HttpErrorResponse && error.status === 401;\r\n }\r\n\r\n static attachAuthorizationHeader(request: HttpRequest<unknown>, accessToken: AccessToken): HttpRequest<unknown> {\r\n return request.clone({\r\n setHeaders: { authorization: `Bearer ${accessToken.token}`, 'auth-source': 'IDMS' },\r\n });\r\n }\r\n\r\n static onAuthorizationError(error: unknown, injector: Injector) {\r\n if (this.options?.onAuthorizationError) {\r\n this.options?.onAuthorizationError(error, injector);\r\n }\r\n\r\n return throwError(() => error);\r\n }\r\n}\r\n","import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http';\r\nimport { catchError, Observable, switchMap } from 'rxjs';\r\nimport { inject, Injector } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { IdentityService } from '../services/identity.service';\r\nimport { RequestHelper } from '../helpers/request.helper';\r\n\r\nexport function requestInterceptor(request: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> {\r\n const identityService = inject(IdentityService);\r\n const injector = inject(Injector);\r\n const router = inject(Router);\r\n\r\n /**\r\n * if it is a request to Identity Service or not an authorized request - do not modify it\r\n */\r\n if (RequestHelper.isIdentityEndpointRequest(request) || !RequestHelper.isAuthorizedRequest(request, router)) {\r\n return next(request);\r\n }\r\n\r\n /**\r\n * if the current user is authenticated - attach the \"Authorization\" header to the request;\r\n * or process the error if it happens\r\n */\r\n return identityService.authenticate().pipe(\r\n catchError((error: unknown) => RequestHelper.onAuthorizationError(error, injector)),\r\n switchMap((accessToken) => next(RequestHelper.attachAuthorizationHeader(request, accessToken))),\r\n );\r\n}\r\n","import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http';\r\nimport { catchError, Observable, switchMap, throwError } from 'rxjs';\r\nimport { inject, Injector } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { IdentityService } from '../services/identity.service';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { RequestHelper } from '../helpers/request.helper';\r\n\r\nexport function responseInterceptor(\r\n request: HttpRequest<unknown>,\r\n next: HttpHandlerFn,\r\n): Observable<HttpEvent<unknown>> {\r\n const options = inject(IDENTITY_OPTIONS);\r\n const identityService = inject(IdentityService);\r\n const injector = inject(Injector);\r\n const router = inject(Router);\r\n\r\n /**\r\n * process all response errors\r\n */\r\n return next(request).pipe(\r\n catchError((error: unknown) => {\r\n /**\r\n * if error happened with Identity Service request, or not-authorized request, or it is not an authorization (401) error -\r\n * do not change anything and return the error as is\r\n */\r\n if (\r\n RequestHelper.isIdentityEndpointRequest(request) ||\r\n !RequestHelper.isAuthorizedRequest(request, router) ||\r\n !RequestHelper.isAuthorizationError(error)\r\n ) {\r\n return throwError(() => error);\r\n }\r\n\r\n /**\r\n * if options do not allow trying and refresh tokens on error 401 -\r\n * process the error and return it\r\n */\r\n if (!options.refreshTokenOnAuthError) {\r\n return RequestHelper.onAuthorizationError(error, injector);\r\n }\r\n\r\n /**\r\n * if tokens were refreshed - attach the \"Authorization\" header to the request and call it again;\r\n * or process the error if it happens\r\n */\r\n return identityService.refreshTokens().pipe(\r\n switchMap((accessToken) => next(RequestHelper.attachAuthorizationHeader(request, accessToken))),\r\n catchError((error: unknown) => RequestHelper.onAuthorizationError(error, injector)),\r\n );\r\n }),\r\n );\r\n}\r\n","import { provideHttpClient, withInterceptors } from '@angular/common/http';\r\nimport { requestInterceptor } from '../interceptors/request.interceptor';\r\nimport { responseInterceptor } from '../interceptors/response.interceptor';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { RequestHelper } from '../helpers/request.helper';\r\nimport { IdentityOptions } from '../types/internal-types';\r\n\r\nexport function provideIdentity(options: IdentityOptions) {\r\n LogHelper.options = options;\r\n RequestHelper.options = options;\r\n\r\n return [\r\n { provide: IDENTITY_OPTIONS, useValue: options },\r\n provideHttpClient(withInterceptors([requestInterceptor, responseInterceptor])),\r\n ];\r\n}\r\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ascentgl-ads-identity.mjs","sources":["../../../../libs/ads-identity/src/lib/helpers/log.helper.ts","../../../../libs/ads-identity/src/lib/helpers/error.helper.ts","../../../../libs/ads-identity/src/lib/helpers/token.helper.ts","../../../../libs/ads-identity/src/lib/types/internal-consts.ts","../../../../libs/ads-identity/src/lib/services/jwks.service.ts","../../../../libs/ads-identity/src/lib/services/token.service.ts","../../../../libs/ads-identity/src/lib/helpers/pkce.helper.ts","../../../../libs/ads-identity/src/lib/services/identity.service.ts","../../../../libs/ads-identity/src/lib/guards/auth.guard.ts","../../../../libs/ads-identity/src/lib/guards/auth-callback.guard.ts","../../../../libs/ads-identity/src/lib/helpers/request.helper.ts","../../../../libs/ads-identity/src/lib/interceptors/request.interceptor.ts","../../../../libs/ads-identity/src/lib/interceptors/response.interceptor.ts","../../../../libs/ads-identity/src/lib/providers/identity.provider.ts"],"sourcesContent":["import { IdentityOptions } from '../types/internal-types';\r\n\r\nexport class LogHelper {\r\n static options?: IdentityOptions;\r\n\r\n private static readonly prefix = 'ADS-IDENTITY';\r\n\r\n static log(...args: unknown[]) {\r\n if (!this.options?.debugMode) return false;\r\n\r\n console.group(this.prefix, 'TOKEN UPDATE');\r\n\r\n console.log(...args);\r\n\r\n console.groupEnd();\r\n\r\n return true;\r\n }\r\n\r\n static error(...args: unknown[]) {\r\n if (!this.options?.debugMode) return false;\r\n\r\n console.group(this.prefix, 'EXCEPTION');\r\n\r\n console.error(...args);\r\n\r\n console.groupEnd();\r\n\r\n return true;\r\n }\r\n}\r\n","import { HttpErrorResponse } from '@angular/common/http';\r\nimport { GenericCollection } from '../types/internal-types';\r\n\r\nexport class ErrorHelper {\r\n static extractMessage(error: unknown): string {\r\n if (typeof error === 'string' && error) {\r\n return error;\r\n }\r\n\r\n let errorMessage: unknown;\r\n\r\n if (error instanceof HttpErrorResponse) {\r\n errorMessage = error.error?.message ?? error.message;\r\n }\r\n\r\n if (!errorMessage && typeof error === 'object' && typeof (<GenericCollection>error)['message'] === 'string') {\r\n errorMessage = (<GenericCollection>error)['message'];\r\n }\r\n\r\n return errorMessage && typeof errorMessage === 'string' ? errorMessage : 'Unknown server error';\r\n }\r\n}\r\n","import { InvalidTokenError, jwtDecode, JwtHeader } from 'jwt-decode';\r\nimport { GenericCollection, IdentityJwtClaim, AccessTokenPayload, RefreshTokenPayload } from '../types/internal-types';\r\nimport { LogHelper } from './log.helper';\r\nimport { ErrorHelper } from './error.helper';\r\n\r\nexport class TokenHelper {\r\n static getPayload<T extends AccessTokenPayload | RefreshTokenPayload>(\r\n token: string,\r\n verifyClaims: GenericCollection = {},\r\n threshold = 0,\r\n ): T {\r\n const payload: T = jwtDecode(token);\r\n\r\n /**\r\n * throw error if the token is expired\r\n */\r\n if (this.isExpired(payload, 'exp', threshold)) {\r\n throw new InvalidTokenError('Token expired');\r\n }\r\n\r\n /**\r\n * loop through claims to verify and make sure the payload matches their values\r\n */\r\n Object.keys(verifyClaims).forEach((claim) => {\r\n const tokenClaimValue = payload[claim];\r\n const requestedClaimValue = verifyClaims[claim];\r\n\r\n if (!this.isClaimValid(tokenClaimValue, requestedClaimValue)) {\r\n throw new InvalidTokenError(\r\n `Invalid \"${claim}\" claim value \"${tokenClaimValue}\" provided in token. Required value is \"${requestedClaimValue}\"`,\r\n );\r\n }\r\n });\r\n\r\n return payload;\r\n }\r\n\r\n /**\r\n * decoded JOSE header (alg/kid) — used to detect asymmetrically signed\r\n * (RS256) tokens that must be verified against the IDMS JWKS. Throws\r\n * InvalidTokenError on malformed input, like every other decoding here.\r\n */\r\n static getHeader(token: string): JwtHeader {\r\n return jwtDecode<JwtHeader>(token, { header: true });\r\n }\r\n\r\n private static isExpired<T extends AccessTokenPayload | RefreshTokenPayload>(\r\n token: T,\r\n claim: IdentityJwtClaim = 'exp',\r\n threshold = 0,\r\n ): boolean {\r\n const throwInvalidColumnError = (column: string): true => {\r\n throw new InvalidTokenError(`Column ${column} does not contain a valid number`);\r\n };\r\n\r\n try {\r\n /**\r\n * get value from the column\r\n */\r\n let timestamp: unknown = token[claim];\r\n\r\n /**\r\n * if values is a number - compare it against the current date\r\n */\r\n if (typeof timestamp === 'number') {\r\n /**\r\n * if a threshold is set - extract it from the timestamp\r\n * NOTE: a threshold allows considering the timestamp expired earlier;\r\n * this allows to make sure the token does not expire while being transferred to backend\r\n */\r\n if (threshold > 0) {\r\n timestamp -= threshold;\r\n }\r\n\r\n return !!timestamp && timestamp * 1000 < new Date().getTime();\r\n }\r\n\r\n return throwInvalidColumnError(claim.toString());\r\n } catch (error: unknown) {\r\n LogHelper.error(new InvalidTokenError(ErrorHelper.extractMessage(error)));\r\n\r\n return true;\r\n }\r\n }\r\n\r\n private static isClaimValid(tokenClaim: unknown, valueToVerify: unknown) {\r\n /**\r\n * if any of the values is an array - apply special logic;\r\n * otherwise do strict comparison\r\n */\r\n if (tokenClaim instanceof Array || valueToVerify instanceof Array) {\r\n /**\r\n * if both claims are arrays - make sure they intersect\r\n */\r\n if (tokenClaim instanceof Array && valueToVerify instanceof Array) {\r\n return tokenClaim.filter((value) => valueToVerify.includes(value)).length > 0;\r\n }\r\n\r\n /**\r\n * if the first claim is an array and the second is a string -\r\n * check if the second is within the first\r\n */\r\n if (tokenClaim instanceof Array && typeof valueToVerify === 'string') {\r\n return tokenClaim.includes(valueToVerify);\r\n }\r\n\r\n /**\r\n * if the second claim is an array and the first is a string -\r\n * check if the first is within the second\r\n */\r\n if (valueToVerify instanceof Array && typeof tokenClaim === 'string') {\r\n return valueToVerify.includes(tokenClaim);\r\n }\r\n\r\n return false;\r\n }\r\n\r\n return tokenClaim === valueToVerify;\r\n }\r\n}\r\n","import { InjectionToken } from '@angular/core';\r\nimport { IdentityOptions } from './internal-types';\r\n\r\nexport const IDENTITY_OPTIONS = new InjectionToken<IdentityOptions>('IDENTITY_OPTIONS');\r\n\r\n/**\r\n * RSASSA-PKCS1-v1_5 with SHA-256 — the one algorithm IDMS signs RS256 tokens with\r\n */\r\nexport const RS256_ALGORITHM = { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' };\r\n","import { inject, Service, signal } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { catchError, defer, from, map, Observable, of, share, switchMap } from 'rxjs';\r\nimport { InvalidTokenError } from 'jwt-decode';\r\nimport { IDENTITY_OPTIONS, RS256_ALGORITHM } from '../types/internal-consts';\r\nimport { Jwks, Nullable } from '../types/internal-types';\r\nimport { TokenHelper } from '../helpers/token.helper';\r\nimport { LogHelper } from '../helpers/log.helper';\r\n\r\n/**\r\n * Verifies RS256-signed IDMS ACCESS tokens against the public keys published\r\n * at {backendUrl}/api/.well-known/jwks.json (Web Crypto, no dependencies).\r\n *\r\n * ARCHITECTURE INVARIANT: only the ACCESS token can be RS256-signed. Refresh\r\n * tokens are ALWAYS HS256 by IDMS design and are never routed through this\r\n * service — their handling is byte-for-byte the pre-JWKS legacy behavior.\r\n *\r\n * The key cache lives in memory only — it dies with the page (by design) and\r\n * is eagerly replaced on every token acquisition (\"until a new access key is\r\n * obtained\"). HS256 tokens cannot be verified client-side and bypass\r\n * everything here.\r\n */\r\n@Service()\r\nexport class JwksService {\r\n private readonly httpClient = inject(HttpClient);\r\n private readonly options = inject(IDENTITY_OPTIONS);\r\n\r\n /** in-memory key cache — signal state, replaced wholesale on every fetch */\r\n private readonly keys = signal<Nullable<Jwks['keys']>>(null);\r\n\r\n /**\r\n * concurrent subscribers join ONE in-flight request (`share`), and the\r\n * connection resets on completion — so the next acquisition fetches anew.\r\n * NOT shareReplay: replaying a completed fetch's body is exactly the stale\r\n * key hazard. The cache-busted channel is a separate stream — a kid-rotation\r\n * retry must never piggyback on an in-flight plain fetch (its body may be\r\n * stale and would false-reject a legitimately rotated key).\r\n */\r\n private readonly keysFetch = defer(() => this.fetchKeys(false)).pipe(share());\r\n private readonly freshKeysFetch = defer(() => this.fetchKeys(true)).pipe(share());\r\n\r\n /**\r\n * acquisition-time check (redeem-code / legacy callback / refresh) for the\r\n * ACCESS token: eagerly refresh the JWKS, then verify the token BEFORE it\r\n * is stored. Errors with InvalidTokenError on a bad signature or unknown\r\n * kid.\r\n *\r\n * Emits SYNCHRONOUSLY for an HS256 token — legacy flows must keep their\r\n * exact timing (and fire no JWKS request at all). Resolves silently when\r\n * the JWKS endpoint is unavailable (unavailability lets the token pass;\r\n * an IDMS blip must not lock users out — mismatches still reject whenever\r\n * keys ARE available).\r\n */\r\n verifyNewToken(token: string): Observable<void> {\r\n /**\r\n * defer so malformed input (getHeader throws) surfaces as an Observable\r\n * error instead of a synchronous throw out of the call site — while the\r\n * HS256 fast path still emits synchronously on subscription\r\n */\r\n return defer(() => {\r\n if (TokenHelper.getHeader(token).alg !== 'RS256') {\r\n return of(undefined);\r\n }\r\n\r\n return this.loadKeys().pipe(switchMap(() => this.assertTokenValid(token)));\r\n });\r\n }\r\n\r\n /**\r\n * read-path check for a localStorage value that is not the current page's\r\n * verified copy (cold reload / cross-tab rotation / tampering). Lazily\r\n * fetches the JWKS when the cache is empty. Emits false ONLY on a definite\r\n * mismatch; unavailability lets the token pass (never locks users out).\r\n */\r\n verifyExistingToken(token: string): Observable<boolean> {\r\n return defer(() => {\r\n if (TokenHelper.getHeader(token).alg !== 'RS256') {\r\n return of(true);\r\n }\r\n\r\n return (this.keys() ? of(true) : this.loadKeys()).pipe(switchMap(() => this.verifyToken(token)));\r\n });\r\n }\r\n\r\n /**\r\n * acquisition gate: turns a failed check into a stream error, so the caller\r\n * can never store a token by forgetting to inspect a boolean\r\n */\r\n private assertTokenValid(token: string): Observable<void> {\r\n return this.verifyToken(token).pipe(\r\n map((valid) => {\r\n if (!valid) {\r\n throw new InvalidTokenError('Token signature verification failed against the IDMS JWKS');\r\n }\r\n }),\r\n );\r\n }\r\n\r\n private verifyToken(token: string): Observable<boolean> {\r\n /**\r\n * keys unavailable (endpoint unreachable and nothing cached) — let the\r\n * token pass rather than lock users out\r\n */\r\n if (!this.keys()) {\r\n return of(true);\r\n }\r\n\r\n const kid = TokenHelper.getHeader(token).kid;\r\n const jwk = this.findKey(kid);\r\n\r\n return jwk ? this.verifySignature(token, jwk) : this.retryWithFreshKeys(token, kid);\r\n }\r\n\r\n /**\r\n * unknown kid against a possibly stale cache: the signing key may have\r\n * rotated since we fetched — force ONE fresh (cache-busted) fetch before\r\n * rejecting. A failed re-fetch cannot distinguish rotation from outage,\r\n * so it also lets the token pass.\r\n */\r\n private retryWithFreshKeys(token: string, kid?: string): Observable<boolean> {\r\n return this.loadKeys(true).pipe(\r\n switchMap((loaded) => {\r\n if (!loaded) {\r\n return of(true);\r\n }\r\n\r\n const rotatedKey = this.findKey(kid);\r\n\r\n return rotatedKey ? this.verifySignature(token, rotatedKey) : of(false);\r\n }),\r\n );\r\n }\r\n\r\n private verifySignature(token: string, jwk: JsonWebKey): Observable<boolean> {\r\n const [header, payload, signature] = token.split('.');\r\n\r\n return defer(() => from(crypto.subtle.importKey('jwk', jwk, RS256_ALGORITHM, false, ['verify']))).pipe(\r\n switchMap((key) =>\r\n from(\r\n crypto.subtle.verify(\r\n RS256_ALGORITHM,\r\n key,\r\n JwksService.fromBase64Url(signature),\r\n new TextEncoder().encode(`${header}.${payload}`),\r\n ),\r\n ),\r\n ),\r\n catchError((error: unknown) => {\r\n LogHelper.error('JWKS verification errored — rejecting token', error);\r\n\r\n return of(false);\r\n }),\r\n );\r\n }\r\n\r\n private loadKeys(fresh = false): Observable<boolean> {\r\n return fresh ? this.freshKeysFetch : this.keysFetch;\r\n }\r\n\r\n private fetchKeys(fresh: boolean): Observable<boolean> {\r\n const url = `${this.options.backendUrl}/api/.well-known/jwks.json`;\r\n\r\n /**\r\n * `fresh` busts the browser HTTP cache (the endpoint serves max-age=3600)\r\n * for the kid-rotation retry — a plain refetching would just replay the\r\n * cached body\r\n */\r\n return this.httpClient.get<Jwks>(fresh ? `${url}?fresh=${Date.now()}` : url).pipe(\r\n map((jwks) => {\r\n this.keys.set(jwks.keys);\r\n\r\n return true;\r\n }),\r\n catchError((error: unknown) => {\r\n LogHelper.error('JWKS endpoint unavailable — failing open', error);\r\n\r\n return of(false);\r\n }),\r\n );\r\n }\r\n\r\n private findKey(kid?: string): Nullable<JsonWebKey> {\r\n return this.keys()?.find((key) => key.kid === kid) ?? null;\r\n }\r\n\r\n /**\r\n * returns Uint8Array<ArrayBuffer> (not the bare-Uint8Array default of\r\n * ArrayBufferLike) — Web Crypto's BufferSource rejects views that could be\r\n * backed by a SharedArrayBuffer\r\n */\r\n private static fromBase64Url(value: string): Uint8Array<ArrayBuffer> {\r\n const binary = atob(value.replace(/-/g, '+').replace(/_/g, '/'));\r\n\r\n return Uint8Array.from(binary, (char) => char.charCodeAt(0));\r\n }\r\n}\r\n","import { computed, inject, Injectable, signal } from '@angular/core';\r\nimport { catchError, map, Observable, of, shareReplay, switchMap } from 'rxjs';\r\nimport { IdentityToken, Nullable } from '../types/internal-types';\r\nimport { AccessToken, RefreshToken } from '../types/global-types';\r\nimport { TokenHelper } from '../helpers/token.helper';\r\nimport { InvalidTokenError } from 'jwt-decode';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { TokenKey } from '../types/internal-enums';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { JwksService } from './jwks.service';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class TokenService {\r\n /**\r\n * NOTE: we expose access and refresh tokens as computed signals so that they can be\r\n * used in \"IdentityService\" to allow library users reactive readonly access to tokens,\r\n * since \"IdentityService\" is the only \"public\" service in the library\r\n */\r\n readonlyAccessToken = computed(() => this.accessToken());\r\n readonlyRefreshToken = computed(() => this.refreshToken());\r\n\r\n private readonly accessToken = signal<Nullable<AccessToken>>(null);\r\n private readonly refreshToken = signal<Nullable<RefreshToken>>(null);\r\n\r\n private readonly options = inject(IDENTITY_OPTIONS);\r\n private readonly jwksService = inject(JwksService);\r\n\r\n /**\r\n * FAIL-CLOSED read gate for the ACCESS token: the token string this page\r\n * has verified (or adopted). A localStorage value that differs is NEVER\r\n * exposed until a background JWKS check adopts it (cold reload / cross-tab\r\n * rotation) or clears everything (tampering). HS256 access tokens bypass\r\n * the gate — they cannot be verified client-side by design.\r\n *\r\n * ARCHITECTURE INVARIANT: refresh tokens are ALWAYS HS256 by IDMS design,\r\n * so only the access token is ever gated/verified; the refresh path is\r\n * byte-for-byte the pre-JWKS legacy behavior.\r\n */\r\n private verifiedAccessToken: Nullable<string> = null;\r\n\r\n /** the single in-flight background verification (access token only) */\r\n private pendingVerification: Nullable<{ token: string; done: Observable<void> }> = null;\r\n\r\n private issuers: string[] = [];\r\n\r\n setAccessToken(token: unknown) {\r\n return this.updateAccessTokenSignal<AccessToken>(this.setToken<AccessToken>(TokenKey.accessToken, token));\r\n }\r\n\r\n getAccessToken() {\r\n return this.updateAccessTokenSignal(this.getToken(TokenKey.accessToken));\r\n }\r\n\r\n setRefreshToken(token: unknown) {\r\n return this.updateRefreshTokenSignal<RefreshToken>(this.setToken(TokenKey.refreshToken, token));\r\n }\r\n\r\n getRefreshToken() {\r\n return this.updateRefreshTokenSignal(this.getToken(TokenKey.refreshToken));\r\n }\r\n\r\n /**\r\n * emits+completes once background verification is quiescent; never errors.\r\n * IdentityService.authenticate() composes this so guarded navigation and\r\n * Bearer attachment wait for the verdict instead of failing on the\r\n * fail-closed null read. Emits synchronously when nothing is pending.\r\n *\r\n * Re-checks after each settled verdict: a NEWER token may have superseded\r\n * the in-flight check while we waited (cross-tab rotation mid-fetch) —\r\n * resolving on the stale verdict alone would send authenticate() into a\r\n * needless token rotation.\r\n */\r\n whenVerified(): Observable<void> {\r\n const pending = this.pendingVerification;\r\n\r\n if (!pending) {\r\n return of(undefined);\r\n }\r\n\r\n return pending.done.pipe(\r\n /**\r\n * recurse ONLY when a different check replaced the slot — the settled\r\n * verdict may replay before our own finalizing clears it, and recursing\r\n * into the same entry would loop forever\r\n */\r\n switchMap(() => (this.pendingVerification === pending ? of(undefined) : this.whenVerified())),\r\n );\r\n }\r\n\r\n /**\r\n * whether background access-token verification is in flight RIGHT NOW.\r\n * whenVerified() only covers checks that existed while it was waiting — a\r\n * read performed AFTER it settles may itself discover a newer unverified\r\n * token and start a fresh check; authenticate() uses this to wait for that\r\n * verdict too instead of treating the fail-closed null read as \"no token\".\r\n */\r\n hasPendingVerification(): boolean {\r\n return this.pendingVerification !== null;\r\n }\r\n\r\n clearTokens() {\r\n localStorage.removeItem(TokenKey.accessToken);\r\n localStorage.removeItem(TokenKey.refreshToken);\r\n\r\n this.updateAccessTokenSignal(null);\r\n this.updateRefreshTokenSignal(null);\r\n\r\n this.verifiedAccessToken = null;\r\n }\r\n\r\n private updateAccessTokenSignal<T extends Nullable<AccessToken>>(newToken: Nullable<AccessToken>): T {\r\n if (this.accessToken()?.token !== newToken?.token) {\r\n this.accessToken.set(newToken);\r\n }\r\n\r\n return <T>this.accessToken();\r\n }\r\n\r\n private updateRefreshTokenSignal<T extends Nullable<RefreshToken>>(newToken: Nullable<RefreshToken>): T {\r\n if (this.refreshToken()?.token !== newToken?.token) {\r\n this.refreshToken.set(newToken);\r\n }\r\n\r\n return <T>this.refreshToken();\r\n }\r\n\r\n private setToken<T extends IdentityToken>(key: TokenKey, token: unknown): T {\r\n /**\r\n * make sure the provided token is at least a string\r\n */\r\n if (typeof token !== 'string') {\r\n throw new InvalidTokenError(`Provided ${key} value is not a string`);\r\n }\r\n\r\n /**\r\n * get identity token\r\n */\r\n const identityToken = this.wrapToken<T>(token);\r\n\r\n /**\r\n * if provided - save it to local storage\r\n */\r\n if (identityToken) {\r\n localStorage.setItem(key, token);\r\n\r\n /**\r\n * acquisition points verify the RS256 access token BEFORE calling the\r\n * setter (JwksService.verifyNewToken) — record the stored string as\r\n * this page's verified copy so reads stay a sync string compare\r\n */\r\n if (key === TokenKey.accessToken) {\r\n this.verifiedAccessToken = token;\r\n }\r\n }\r\n\r\n LogHelper.log(key, identityToken);\r\n\r\n return identityToken;\r\n }\r\n\r\n private getToken<T extends IdentityToken>(key: TokenKey): Nullable<T> {\r\n /**\r\n * get token value from local storage or use null\r\n */\r\n const actualToken = localStorage.getItem(key) ?? null;\r\n\r\n if (typeof actualToken === 'string') {\r\n try {\r\n /**\r\n * FAIL CLOSED (access token only — refresh tokens are ALWAYS HS256\r\n * by IDMS architecture and take the legacy path below): an RS256\r\n * access token that is not this page's verified copy is not exposed —\r\n * verify it in the background and report \"no token\" meanwhile\r\n * (authenticate() awaits the verdict via whenVerified())\r\n */\r\n if (key === TokenKey.accessToken && !this.isVerified(actualToken)) {\r\n this.verifyInBackground(actualToken);\r\n\r\n return null;\r\n }\r\n\r\n return this.wrapToken<T>(actualToken);\r\n } catch (error) {\r\n LogHelper.error(error);\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n private isVerified(token: string): boolean {\r\n /**\r\n * only asymmetric (RS256) tokens are verifiable client-side; anything\r\n * else behaves exactly as before this feature existed\r\n */\r\n if (TokenHelper.getHeader(token).alg !== 'RS256') {\r\n return true;\r\n }\r\n\r\n return this.verifiedAccessToken === token;\r\n }\r\n\r\n private verifyInBackground(token: string) {\r\n /**\r\n * one in-flight check per token value; repeated sync reads while the\r\n * verdict is pending must not stack up requests\r\n */\r\n if (this.pendingVerification?.token === token) {\r\n return;\r\n }\r\n\r\n const done = this.jwksService.verifyExistingToken(token).pipe(\r\n /**\r\n * an ERROR from the verification (e.g., malformed token) is treated\r\n * exactly like failed verification — whenVerified() must never error\r\n */\r\n catchError((error: unknown) => {\r\n LogHelper.error(error);\r\n\r\n return of(false);\r\n }),\r\n map((valid) => {\r\n /**\r\n * Clear the slot BEFORE applying the verdict: authenticate() re-reads\r\n * synchronously as the verdict emits, and a still-set slot makes\r\n * hasPendingVerification() loop forever on a token that verifies but\r\n * can't be read (wrong iss/sub). A newer token re-registers after this.\r\n */\r\n if (this.pendingVerification?.token === token) {\r\n this.pendingVerification = null;\r\n }\r\n\r\n return this.applyVerdict(token, valid);\r\n }),\r\n /**\r\n * late whenVerified() subscribers must still observe the settled verdict\r\n */\r\n shareReplay(1),\r\n );\r\n\r\n this.pendingVerification = { token, done };\r\n\r\n /**\r\n * kick the background check off immediately — reads are sync and never\r\n * subscribe themselves\r\n */\r\n done.subscribe();\r\n }\r\n\r\n private applyVerdict(token: string, valid: boolean): void {\r\n /**\r\n * the stored value moved on while we verified (another tab rotated it, or\r\n * clearTokens ran) — this verdict is about a token nobody holds anymore\r\n */\r\n if (localStorage.getItem(TokenKey.accessToken) !== token) {\r\n return;\r\n }\r\n\r\n if (!valid) {\r\n /**\r\n * definite mismatch = tampering; drop everything and force a re-login\r\n * on the next guarded navigation\r\n */\r\n LogHelper.error(new InvalidTokenError('Stored access token failed JWKS signature verification'));\r\n\r\n return this.clearTokens();\r\n }\r\n\r\n /**\r\n * verify-then-adopt: a legit cold reload or another tab rotated the\r\n * token — adopt and re-read so the signal refreshes for reactive\r\n * consumers\r\n */\r\n this.verifiedAccessToken = token;\r\n\r\n this.getAccessToken();\r\n }\r\n\r\n private wrapToken<T extends IdentityToken>(token: string): T {\r\n /**\r\n * parse a token and get its payload\r\n * NOTE: errors will be thrown if the token is expired or has invalid claims\r\n */\r\n const payload = TokenHelper.getPayload(\r\n token,\r\n {\r\n iss: this.getIssuers(),\r\n sub: this.options.application,\r\n },\r\n 60,\r\n );\r\n\r\n /**\r\n * return identity token object\r\n */\r\n return <T>{ token, payload: payload };\r\n }\r\n\r\n private getIssuers(): string[] {\r\n /**\r\n * if we already have issuers - ise them\r\n */\r\n if (this.issuers.length) {\r\n return this.issuers;\r\n }\r\n\r\n /**\r\n * get issuer value from the options\r\n */\r\n const issuer = this.options.serviceIssuer ?? this.options.backendUrl;\r\n\r\n this.issuers = [issuer];\r\n\r\n /**\r\n * make sure we have both variants (with and without \"/api\" suffix) as issuers\r\n * todo \"/api\" suffix verification must be removed when \"/api\" suffix will be removed from the \"issuer\" in IDMS\r\n */\r\n if (issuer.endsWith('/api')) {\r\n this.issuers.push(issuer.substring(0, issuer.lastIndexOf('/api')));\r\n } else {\r\n this.issuers.push(`${issuer}/api`);\r\n }\r\n\r\n return this.issuers;\r\n }\r\n}\r\n","import { TokenKey } from '../types/internal-enums';\r\n\r\n/**\r\n * PKCE (RFC 7636, S256) for the code-flow app launch.\r\n *\r\n * The `code_verifier` is a secret kept in `localStorage` across the\r\n * app → IDMS → app round trip. localStorage — NOT sessionStorage — because the\r\n * round trip crosses origins and, under browser site-isolation, swaps renderer\r\n * processes; a per-tab sessionStorage write made just before the outbound\r\n * redirect can fail to survive to the callback (observed as an empty verifier at\r\n * redeem). localStorage is durable and same-origin-shared, so the callback always\r\n * reads it back; it is cleared on redemption (single-use). Only the\r\n * `code_challenge` (its SHA-256 hash) travels on the outbound redirect URL. IDMS\r\n * bakes the challenge into the one-time code and verifies the presented verifier\r\n * at `POST /redeem-code`.\r\n */\r\nexport class PkceHelper {\r\n /**\r\n * 43-char base64url verifier from 32 CSPRNG bytes — inside RFC 7636's 43–128\r\n * range, unreserved charset (base64url ⊂ unreserved).\r\n */\r\n static createVerifier(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n return PkceHelper.toBase64Url(bytes);\r\n }\r\n\r\n /** `BASE64URL(SHA256(verifier))` — the S256 challenge (RFC 7636 §4.2). */\r\n static async createChallenge(verifier: string): Promise<string> {\r\n const digest = await crypto.subtle.digest(\r\n 'SHA-256',\r\n new TextEncoder().encode(verifier),\r\n );\r\n return PkceHelper.toBase64Url(new Uint8Array(digest));\r\n }\r\n\r\n /**\r\n * Generate a verifier, stash it for the pending `/redeem-code`, and build the\r\n * IDMS login redirect URL carrying the S256 challenge. Returned (not applied)\r\n * so the caller assigns `window.location.href` — keeps this unit testable\r\n * without triggering navigation.\r\n */\r\n static async buildLoginRedirectUrl(\r\n options: { frontendUrl: string; application: string },\r\n redirectPath: string,\r\n ): Promise<string> {\r\n const verifier = PkceHelper.createVerifier();\r\n const challenge = await PkceHelper.createChallenge(verifier);\r\n\r\n localStorage.setItem(TokenKey.pkceVerifier, verifier);\r\n\r\n return (\r\n `${options.frontendUrl}/apps/${options.application}` +\r\n `?redirect=true&redirect_path=${encodeURIComponent(redirectPath)}` +\r\n `&code_challenge=${challenge}&code_challenge_method=S256`\r\n );\r\n }\r\n\r\n /** The verifier stashed for the pending redemption (or `null`). */\r\n static readVerifier(): string | null {\r\n return localStorage.getItem(TokenKey.pkceVerifier);\r\n }\r\n\r\n static clearVerifier(): void {\r\n localStorage.removeItem(TokenKey.pkceVerifier);\r\n }\r\n\r\n private static toBase64Url(bytes: Uint8Array): string {\r\n let binary = '';\r\n for (const byte of bytes) {\r\n binary += String.fromCharCode(byte);\r\n }\r\n return btoa(binary)\r\n .replace(/\\+/g, '-')\r\n .replace(/\\//g, '_')\r\n .replace(/=+$/, '');\r\n }\r\n}\r\n","import { computed, inject, Injectable } from '@angular/core';\r\nimport {\r\n catchError,\r\n finalize,\r\n map,\r\n Observable,\r\n of,\r\n shareReplay,\r\n switchMap,\r\n throwError,\r\n} from 'rxjs';\r\nimport { TokenService } from './token.service';\r\nimport { JwksService } from './jwks.service';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { Nullable, RefreshTokenResponse } from '../types/internal-types';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { PkceHelper } from '../helpers/pkce.helper';\r\nimport { AccessToken } from '../types/global-types';\r\nimport { InvalidTokenError } from 'jwt-decode';\r\nimport { ErrorHelper } from '../helpers/error.helper';\r\nimport { IdentityServiceInterface } from '../interfaces/identity-service.interface';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class IdentityService implements IdentityServiceInterface {\r\n /**\r\n * NOTE: we expose access and refresh tokens as computed signals to allow\r\n * library users reactive readonly access to tokens, since \"IdentityService\"\r\n * is the only \"public\" service in the library\r\n */\r\n readonly accessToken = computed(() => this.tokenService.readonlyAccessToken());\r\n readonly refreshToken = computed(() => this.tokenService.readonlyRefreshToken());\r\n\r\n private refreshInProgress: Nullable<Observable<AccessToken>> = null;\r\n\r\n private readonly tokenService = inject(TokenService);\r\n private readonly jwksService = inject(JwksService);\r\n private readonly httpClient = inject(HttpClient);\r\n private readonly options = inject(IDENTITY_OPTIONS);\r\n\r\n isAuthenticated() {\r\n return !!this.tokenService.getAccessToken();\r\n }\r\n\r\n authenticate(): Observable<AccessToken> {\r\n /**\r\n * get access token (the read also starts the background JWKS check when\r\n * the stored RS256 token is not verified yet)\r\n */\r\n const accessToken = this.tokenService.getAccessToken();\r\n\r\n /**\r\n * if it is available - return it (synchronous fast path — unchanged for\r\n * verified/HS256 tokens)\r\n */\r\n if (accessToken) {\r\n return of(accessToken);\r\n }\r\n\r\n /**\r\n * the access token read may be null because background JWKS\r\n * verification is still in flight (cold reload / cross-tab rotation) —\r\n * ALWAYS wait for that verdict before deciding, and only then fall back\r\n * to the refresh token. Deciding on the refresh token early would turn\r\n * every cold reload of a valid RS256 session into a needless token\r\n * rotation (refresh tokens are always HS256, so they read as available\r\n * while the access verdict is still pending). With no verification\r\n * pending, whenVerified() emits synchronously — legacy timing unchanged.\r\n */\r\n return this.decideWhenQuiescent();\r\n }\r\n\r\n /**\r\n * wait for any in-flight background verification, then decide from FRESH\r\n * reads. Recurses when the deciding re-read itself discovers a newer\r\n * unverified token (cross-tab rotation landing between a settled verdict\r\n * and the re-read — a check whenVerified() could not have covered because\r\n * it did not exist yet); otherwise that read's fail-closed null would be\r\n * mistaken for \"no token\" and trigger a needless rotation. Each recursion\r\n * consumes a real async verdict, so this terminates as soon as rotations\r\n * stop. Legacy HS256 reads never start a check — for them everything here\r\n * stays synchronous and same-tick.\r\n */\r\n private decideWhenQuiescent(): Observable<AccessToken> {\r\n return this.tokenService.whenVerified().pipe(\r\n switchMap(() => {\r\n const verifiedAccessToken = this.tokenService.getAccessToken();\r\n\r\n if (verifiedAccessToken) {\r\n return of(verifiedAccessToken);\r\n }\r\n\r\n if (this.tokenService.hasPendingVerification()) {\r\n return this.decideWhenQuiescent();\r\n }\r\n\r\n if (this.tokenService.getRefreshToken()) {\r\n return this.refreshTokens();\r\n }\r\n\r\n /**\r\n * throw error if no tokens are available\r\n */\r\n return throwError(() => new InvalidTokenError('No valid tokens found'));\r\n }),\r\n );\r\n }\r\n\r\n refreshTokens(): Observable<AccessToken> {\r\n if (this.refreshInProgress) return this.refreshInProgress;\r\n\r\n this.refreshInProgress = this.performRefresh().pipe(\r\n catchError((error: unknown) => {\r\n this.refreshInProgress = null;\r\n return throwError(() => error);\r\n }),\r\n finalize(() => {\r\n this.refreshInProgress = null;\r\n }),\r\n shareReplay(1),\r\n );\r\n\r\n return this.refreshInProgress;\r\n }\r\n\r\n clearTokens() {\r\n this.tokenService.clearTokens();\r\n }\r\n\r\n /**\r\n * exchange a one-time authorization code (delivered in the app callback by a\r\n * code-enabled IDMS app) for the SAME token pair the legacy tokens-in-URL\r\n * callback delivers. Storage is the caller's job (the auth-callback guard),\r\n * mirroring how the guard stores tokens today.\r\n *\r\n * NOTE: `redirect_uri` MUST equal this app's IDMS `loginUrl` — i.e., the\r\n * callback route we are currently on — so IDMS's bind-check on redemption\r\n * passes. We derive it from the current location.\r\n *\r\n * PKCE (RFC 7636): send the `code_verifier` stashed by the launch redirect\r\n * (PkceHelper); IDMS re-hashes it against the code's challenge. Cleared on\r\n * success — it is single-use like the code.\r\n */\r\n redeemCode(code: string): Observable<RefreshTokenResponse> {\r\n /**\r\n * the verifier is single-use — read it and drop it immediately, regardless\r\n * of the redeem outcome. The value is captured in the request body below, so\r\n * a failed/replayed attempt never leaves a spent verifier in localStorage.\r\n */\r\n const codeVerifier = PkceHelper.readVerifier();\r\n PkceHelper.clearVerifier();\r\n\r\n /**\r\n * no verifier stored → the launch-time write was lost. Fail LOUD instead of\r\n * POSTing `code_verifier: ''`: an empty verifier can never satisfy IDMS's PKCE\r\n * check, and sending it would burn the one-time code for good. Aborting leaves\r\n * the code unspent, so simply re-launching the app succeeds.\r\n */\r\n if (!codeVerifier) {\r\n return throwError(() => new InvalidTokenError('Missing PKCE verifier; cannot redeem code'));\r\n }\r\n\r\n return this.httpClient\r\n .post<RefreshTokenResponse>(\r\n `${this.options.backendUrl}/api/v${this.options.apiVersion ?? 1}/redeem-code`,\r\n {\r\n code,\r\n client_id: this.options.application,\r\n redirect_uri: `${window.location.origin}${window.location.pathname}`,\r\n code_verifier: codeVerifier,\r\n },\r\n )\r\n .pipe(\r\n switchMap((response) =>\r\n /**\r\n * verify the RS256 access token against a fresh JWKS BEFORE handing\r\n * the pair to the caller (the callback guard stores them); HS256\r\n * access tokens pass through synchronously untouched. The refresh\r\n * token is ALWAYS HS256 (IDMS architecture) and is never verified.\r\n */\r\n this.jwksService.verifyNewToken(response.access_token).pipe(map(() => response)),\r\n ),\r\n );\r\n }\r\n\r\n private performRefresh() {\r\n const refreshToken = this.tokenService.getRefreshToken();\r\n\r\n /**\r\n * throw error if the refresh token is not available\r\n */\r\n if (!refreshToken) {\r\n return throwError(() => new InvalidTokenError('No refresh token found'));\r\n }\r\n\r\n /**\r\n * make a request to Identity service to get new tokens\r\n */\r\n return this.httpClient\r\n .get<RefreshTokenResponse>(`${this.options.backendUrl}/api/v${this.options.apiVersion ?? 1}/refresh-token`, {\r\n headers: { Authorization: `Bearer ${refreshToken.token}` },\r\n })\r\n .pipe(\r\n catchError((error: unknown) => {\r\n /**\r\n * log error if it happens\r\n */\r\n LogHelper.error(\r\n new InvalidTokenError(\r\n `Failed to obtain tokens. Reason: ${ErrorHelper.extractMessage(error).toLowerCase()}`,\r\n ),\r\n );\r\n\r\n return throwError(() => error);\r\n }),\r\n switchMap((response) =>\r\n /**\r\n * \"new access key obtained\" — eagerly refresh the JWKS cache and\r\n * verify the RS256 access token BEFORE anything is stored (the\r\n * refresh token is ALWAYS HS256 and is never verified)\r\n */\r\n this.jwksService.verifyNewToken(response.access_token).pipe(map(() => response)),\r\n ),\r\n map((response) => {\r\n /**\r\n * set refresh token\r\n */\r\n this.tokenService.setRefreshToken(response.refresh_token);\r\n\r\n /**\r\n * set and return access token\r\n */\r\n return this.tokenService.setAccessToken(response.access_token);\r\n }),\r\n );\r\n }\r\n}\r\n","import { CanActivateFn } from '@angular/router';\r\nimport { inject } from '@angular/core';\r\nimport { IdentityService } from '../services/identity.service';\r\nimport { catchError, from, map } from 'rxjs';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { PkceHelper } from '../helpers/pkce.helper';\r\n\r\nexport const IDENTITY_AUTH_GUARD: CanActivateFn = (_route, state) => {\r\n const identityService = inject(IdentityService);\r\n const options = inject(IDENTITY_OPTIONS);\r\n\r\n /**\r\n * check if the user is authenticated;\r\n * if an error happened - redirect to IDMS url to re-login;\r\n * return true on success and false on error\r\n */\r\n return identityService.authenticate().pipe(\r\n catchError((error) => {\r\n LogHelper.error(error);\r\n\r\n /**\r\n * no session → re-login. PKCE: stash a code_verifier and redirect to IDMS\r\n * with the S256 code_challenge so the code IDMS mints are bound to this\r\n * client (verified back at POST /redeem-code).\r\n */\r\n return from(PkceHelper.buildLoginRedirectUrl(options, state.url)).pipe(\r\n map((url) => {\r\n window.location.href = url;\r\n\r\n return null;\r\n }),\r\n );\r\n }),\r\n map((accessToken) => !!accessToken),\r\n );\r\n};\r\n","import { CanActivateFn, Router } from '@angular/router';\r\nimport { inject } from '@angular/core';\r\nimport { catchError, from, map, of, switchMap } from 'rxjs';\r\nimport { TokenService } from '../services/token.service';\r\nimport { IdentityService } from '../services/identity.service';\r\nimport { JwksService } from '../services/jwks.service';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { ErrorHelper } from '../helpers/error.helper';\r\nimport { PkceHelper } from '../helpers/pkce.helper';\r\n\r\nexport const IDENTITY_AUTH_CALLBACK_GUARD: CanActivateFn = (route) => {\r\n const router = inject(Router);\r\n const tokenService = inject(TokenService);\r\n const identityService = inject(IdentityService);\r\n const jwksService = inject(JwksService);\r\n const options = inject(IDENTITY_OPTIONS);\r\n\r\n /**\r\n * display an error message on the page and return false to stop further\r\n * navigation; text (not HTML) because the message may embed attacker-controlled\r\n * JWT claim values from the callback query param (innerHTML would be XSS)\r\n */\r\n const denyWithError = (error: unknown) => {\r\n const routerOutlet = document.body.querySelector('router-outlet');\r\n\r\n if (routerOutlet) {\r\n routerOutlet.textContent = ErrorHelper.extractMessage(error);\r\n }\r\n\r\n LogHelper.error(error);\r\n\r\n return false;\r\n };\r\n\r\n const applyTokens = (accessToken: string, refreshToken: string) => {\r\n tokenService.setAccessToken(accessToken);\r\n\r\n tokenService.setRefreshToken(refreshToken);\r\n\r\n return router.navigateByUrl(route.queryParams['redirect_path'] || '/');\r\n };\r\n\r\n const code = route.queryParams['code'];\r\n\r\n /**\r\n * bare launch: IDMS had a session but was launched with no redirect_path, so\r\n * it minted no code and sent us here with `code=none`. Re-login *explicitly*\r\n * with a redirect_path so IDMS mints a real code. The redirect_path MUST be\r\n * non-empty, or IDMS returns `code=none` again (infinite loop) — a bare launch\r\n * has no deep-link target, so falls back to the app root, exactly as the token\r\n * path below does for navigation.\r\n */\r\n if (code === 'none') {\r\n // re-login WITH a redirect_path (loop guard) and, like the auth guard, a\r\n // fresh PKCE challenge so IDMS can mint a code bound to this client.\r\n return from(\r\n PkceHelper.buildLoginRedirectUrl(\r\n options,\r\n route.queryParams['redirect_path'] || '/',\r\n ),\r\n ).pipe(\r\n map((url) => {\r\n window.location.href = url;\r\n\r\n return false;\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * code-enabled app: exchange the one-time code for the same token pair the\r\n * legacy path receives, store it (as below), and navigate to redirect_path.\r\n */\r\n if (code) {\r\n return identityService.redeemCode(code).pipe(\r\n switchMap(response => applyTokens(response.access_token, response.refresh_token)),\r\n catchError((error: unknown) => of(denyWithError(error))),\r\n );\r\n }\r\n\r\n if (!route.queryParams['access_token'] || !route.queryParams['refresh_token']) {\r\n return denyWithError('No access or refresh token provided');\r\n }\r\n\r\n /**\r\n * legacy tokens-in-URL: verify the RS256 access token against a fresh JWKS\r\n * BEFORE the tokens are stored (an HS256 access token passes through\r\n * synchronously untouched; the refresh token is ALWAYS HS256 by IDMS\r\n * architecture and is never verified). setAccessToken/setRefreshToken still\r\n * decode+validate and throw on an expired/invalid token; both failure kinds\r\n * surface as the error page via catchError (the code branch above gets the\r\n * same treatment).\r\n */\r\n return jwksService.verifyNewToken(route.queryParams['access_token']).pipe(\r\n switchMap(() => applyTokens(route.queryParams['access_token'], route.queryParams['refresh_token'])),\r\n catchError((error: unknown) => of(denyWithError(error))),\r\n );\r\n};\r\n","import { HttpErrorResponse, HttpRequest } from '@angular/common/http';\r\nimport { throwError } from 'rxjs';\r\nimport { Injector } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { IdentityOptions } from '../types/internal-types';\r\nimport { AccessToken } from '../types/global-types';\r\nimport { IDENTITY_AUTH_GUARD } from '../guards/auth.guard';\r\n\r\nexport class RequestHelper {\r\n static options?: IdentityOptions;\r\n\r\n static isIdentityEndpointRequest(request: HttpRequest<unknown>): boolean {\r\n return (\r\n (!!this.options?.backendUrl && request.url.startsWith(this.options?.backendUrl)) ||\r\n (!!this.options?.frontendUrl && request.url.startsWith(this.options?.frontendUrl))\r\n );\r\n }\r\n\r\n static isAuthorizedRequest(request: HttpRequest<unknown>, router: Router): boolean {\r\n return this.isRouteGuarded(router) && (!this.options?.requestFilter || this.options.requestFilter(request));\r\n }\r\n\r\n /**\r\n * a request is authorized only when the active route (or one of its\r\n * ancestors) is protected by IDENTITY_AUTH_GUARD, so unguarded pages never\r\n * trigger authentication\r\n */\r\n private static isRouteGuarded(router: Router): boolean {\r\n let route = router.routerState.snapshot.root.firstChild;\r\n\r\n while (route) {\r\n const guards = [...(route.routeConfig?.canActivate ?? []), ...(route.routeConfig?.canActivateChild ?? [])];\r\n\r\n if (guards.includes(IDENTITY_AUTH_GUARD)) {\r\n return true;\r\n }\r\n\r\n // ponytail: primary outlet only; recurse children if named-outlet guards ever matter\r\n route = route.firstChild;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n static isAuthorizationError(error: unknown): boolean {\r\n return error instanceof HttpErrorResponse && error.status === 401;\r\n }\r\n\r\n static attachAuthorizationHeader(request: HttpRequest<unknown>, accessToken: AccessToken): HttpRequest<unknown> {\r\n return request.clone({\r\n setHeaders: { authorization: `Bearer ${accessToken.token}`, 'auth-source': 'IDMS' },\r\n });\r\n }\r\n\r\n static onAuthorizationError(error: unknown, injector: Injector) {\r\n if (this.options?.onAuthorizationError) {\r\n this.options?.onAuthorizationError(error, injector);\r\n }\r\n\r\n return throwError(() => error);\r\n }\r\n}\r\n","import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http';\r\nimport { catchError, Observable, switchMap } from 'rxjs';\r\nimport { inject, Injector } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { IdentityService } from '../services/identity.service';\r\nimport { RequestHelper } from '../helpers/request.helper';\r\n\r\nexport function requestInterceptor(request: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> {\r\n const identityService = inject(IdentityService);\r\n const injector = inject(Injector);\r\n const router = inject(Router);\r\n\r\n /**\r\n * if it is a request to Identity Service or not an authorized request - do not modify it\r\n */\r\n if (RequestHelper.isIdentityEndpointRequest(request) || !RequestHelper.isAuthorizedRequest(request, router)) {\r\n return next(request);\r\n }\r\n\r\n /**\r\n * if the current user is authenticated - attach the \"Authorization\" header to the request;\r\n * or process the error if it happens\r\n */\r\n return identityService.authenticate().pipe(\r\n catchError((error: unknown) => RequestHelper.onAuthorizationError(error, injector)),\r\n switchMap((accessToken) => next(RequestHelper.attachAuthorizationHeader(request, accessToken))),\r\n );\r\n}\r\n","import { HttpEvent, HttpHandlerFn, HttpRequest } from '@angular/common/http';\r\nimport { catchError, Observable, switchMap, throwError } from 'rxjs';\r\nimport { inject, Injector } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { IdentityService } from '../services/identity.service';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { RequestHelper } from '../helpers/request.helper';\r\n\r\nexport function responseInterceptor(\r\n request: HttpRequest<unknown>,\r\n next: HttpHandlerFn,\r\n): Observable<HttpEvent<unknown>> {\r\n const options = inject(IDENTITY_OPTIONS);\r\n const identityService = inject(IdentityService);\r\n const injector = inject(Injector);\r\n const router = inject(Router);\r\n\r\n /**\r\n * process all response errors\r\n */\r\n return next(request).pipe(\r\n catchError((error: unknown) => {\r\n /**\r\n * if error happened with Identity Service request, or not-authorized request, or it is not an authorization (401) error -\r\n * do not change anything and return the error as is\r\n */\r\n if (\r\n RequestHelper.isIdentityEndpointRequest(request) ||\r\n !RequestHelper.isAuthorizedRequest(request, router) ||\r\n !RequestHelper.isAuthorizationError(error)\r\n ) {\r\n return throwError(() => error);\r\n }\r\n\r\n /**\r\n * if options do not allow trying and refresh tokens on error 401 -\r\n * process the error and return it\r\n */\r\n if (!options.refreshTokenOnAuthError) {\r\n return RequestHelper.onAuthorizationError(error, injector);\r\n }\r\n\r\n /**\r\n * if tokens were refreshed - attach the \"Authorization\" header to the request and call it again;\r\n * or process the error if it happens\r\n */\r\n return identityService.refreshTokens().pipe(\r\n switchMap((accessToken) => next(RequestHelper.attachAuthorizationHeader(request, accessToken))),\r\n catchError((error: unknown) => RequestHelper.onAuthorizationError(error, injector)),\r\n );\r\n }),\r\n );\r\n}\r\n","import { provideHttpClient, withInterceptors } from '@angular/common/http';\r\nimport { requestInterceptor } from '../interceptors/request.interceptor';\r\nimport { responseInterceptor } from '../interceptors/response.interceptor';\r\nimport { IDENTITY_OPTIONS } from '../types/internal-consts';\r\nimport { LogHelper } from '../helpers/log.helper';\r\nimport { RequestHelper } from '../helpers/request.helper';\r\nimport { IdentityOptions } from '../types/internal-types';\r\n\r\nexport function provideIdentity(options: IdentityOptions) {\r\n LogHelper.options = options;\r\n RequestHelper.options = options;\r\n\r\n return [\r\n { provide: IDENTITY_OPTIONS, useValue: options },\r\n provideHttpClient(withInterceptors([requestInterceptor, responseInterceptor])),\r\n ];\r\n}\r\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED