@anarchitects/auth-angular 0.5.1 → 0.6.0
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.
- package/README.md +40 -16
- package/data-access/README.md +6 -8
- package/data-access/jwt/README.md +23 -0
- package/feature/README.md +7 -5
- package/feature/jwt/README.md +27 -0
- package/fesm2022/anarchitects-auth-angular-config.mjs +20 -2
- package/fesm2022/anarchitects-auth-angular-config.mjs.map +1 -1
- package/fesm2022/anarchitects-auth-angular-data-access-jwt.mjs +201 -0
- package/fesm2022/anarchitects-auth-angular-data-access-jwt.mjs.map +1 -0
- package/fesm2022/anarchitects-auth-angular-data-access.mjs +5 -174
- package/fesm2022/anarchitects-auth-angular-data-access.mjs.map +1 -1
- package/fesm2022/anarchitects-auth-angular-feature-jwt.mjs +26 -0
- package/fesm2022/anarchitects-auth-angular-feature-jwt.mjs.map +1 -0
- package/fesm2022/anarchitects-auth-angular-feature.mjs +4 -75
- package/fesm2022/anarchitects-auth-angular-feature.mjs.map +1 -1
- package/fesm2022/anarchitects-auth-angular-state-jwt.mjs +66 -0
- package/fesm2022/anarchitects-auth-angular-state-jwt.mjs.map +1 -0
- package/fesm2022/anarchitects-auth-angular-state.mjs +6 -74
- package/fesm2022/anarchitects-auth-angular-state.mjs.map +1 -1
- package/fesm2022/anarchitects-auth-angular-ui-jwt.mjs +58 -0
- package/fesm2022/anarchitects-auth-angular-ui-jwt.mjs.map +1 -0
- package/fesm2022/anarchitects-auth-angular-ui.mjs +6 -77
- package/fesm2022/anarchitects-auth-angular-ui.mjs.map +1 -1
- package/package.json +18 -2
- package/state/README.md +3 -2
- package/state/jwt/README.md +22 -0
- package/types/anarchitects-auth-angular-config.d.ts +8 -1
- package/types/anarchitects-auth-angular-data-access-jwt.d.ts +45 -0
- package/types/anarchitects-auth-angular-data-access.d.ts +15 -31
- package/types/anarchitects-auth-angular-feature-jwt.d.ts +13 -0
- package/types/anarchitects-auth-angular-feature.d.ts +2 -13
- package/types/anarchitects-auth-angular-state-jwt.d.ts +19 -0
- package/types/anarchitects-auth-angular-state.d.ts +3 -10
- package/types/anarchitects-auth-angular-ui-jwt.d.ts +17 -0
- package/types/anarchitects-auth-angular-ui.d.ts +3 -18
- package/ui/README.md +2 -1
- package/ui/jwt/README.md +11 -0
package/README.md
CHANGED
|
@@ -2,19 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
Angular domain libraries for the Anarchitecture auth domain. The package is organized into standalone slices (config, data-access, feature, state, util, ui) that compose implementation-aligned authentication flows for Angular applications.
|
|
4
4
|
|
|
5
|
+
Migration guidance for the Better Auth realignment lives in the [auth migration guide](../../../docs/guides/auth-migration.md).
|
|
6
|
+
|
|
5
7
|
## Developer + AI Agent Start Here
|
|
6
8
|
|
|
7
9
|
- Read this README before generating integration code for `@anarchitects/auth-angular`.
|
|
8
|
-
- Use public entry points only (`config`, `data-access`, `feature`, `state`, `util`, `ui`); do not import internal files.
|
|
9
|
-
- Register providers and state explicitly via `provideAuthConfig`, `
|
|
10
|
+
- Use public entry points only (`config`, `data-access`, `feature`, `state`, `util`, `ui`, plus layer-scoped plugin subpaths like `data-access/jwt`); do not import internal files.
|
|
11
|
+
- Register providers and state explicitly via `provideAuthConfig`, Angular `provideHttpClient(...)`, and `provideAuthState`.
|
|
10
12
|
- Keep policy and ability behavior aligned with contracts from `@anarchitects/auth-ts`.
|
|
11
13
|
- Preserve Angular layering and keep orchestration out of UI components.
|
|
12
14
|
|
|
13
15
|
## Features
|
|
14
16
|
|
|
15
|
-
- `config`: DI tokens and provider helpers (API
|
|
17
|
+
- `config`: DI tokens and provider helpers (API resource path, defaults)
|
|
16
18
|
- `data-access`: generated OpenAPI clients plus adapters over the Nest API
|
|
17
|
-
- `state`: signal-based store plus explicit provider helper for login/logout,
|
|
19
|
+
- `state`: signal-based store plus explicit provider helper for core session login/logout, eager session restore, and ability hydration
|
|
18
20
|
- `feature`: coarse route guard, resource-aware route guard, and orchestration components that delegate rendering to auth UI components
|
|
19
21
|
- `util`: CASL ability helpers (`createAppAbility`, `canAccessResource`, `canAccessResourceField`, `AppAbility`)
|
|
20
22
|
- `ui`: presentational auth domain form components built on `AnarchitectsUiForm`
|
|
@@ -50,18 +52,17 @@ The internal `@anarchitects/auth-ts`, `@anarchitects/forms-angular`, `@anarchite
|
|
|
50
52
|
### Quick start
|
|
51
53
|
|
|
52
54
|
```ts
|
|
53
|
-
// app.config.ts
|
|
54
55
|
import { ApplicationConfig } from '@angular/core';
|
|
56
|
+
import { provideHttpClient, withFetch } from '@angular/common/http';
|
|
55
57
|
import { provideAuthConfig } from '@anarchitects/auth-angular/config';
|
|
56
|
-
import { provideAuthDataAccess } from '@anarchitects/auth-angular/data-access';
|
|
57
58
|
import { provideAuthState } from '@anarchitects/auth-angular/state';
|
|
58
59
|
|
|
59
60
|
export const appConfig: ApplicationConfig = {
|
|
60
61
|
providers: [
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
provideHttpClient(withFetch()),
|
|
63
|
+
...provideAuthConfig({
|
|
64
|
+
apiResourcePath: 'auth',
|
|
63
65
|
}),
|
|
64
|
-
provideAuthDataAccess(),
|
|
65
66
|
...provideAuthState(),
|
|
66
67
|
],
|
|
67
68
|
};
|
|
@@ -122,6 +123,23 @@ export const routes: Routes = [
|
|
|
122
123
|
|
|
123
124
|
`policyGuard` is a coarse route-attempt guard. It answers "may this user attempt work on this subject at all?" by using the shared route matcher from `@anarchitects/auth-ts`. Concrete ownership checks still belong to loaded resources. Use `resourcePolicyGuard` for resolved edit/detail routes and `canAccessResource(...)` / `canAccessResourceField(...)` for UI elements such as edit buttons.
|
|
124
125
|
|
|
126
|
+
### Optional JWT plugin wiring
|
|
127
|
+
|
|
128
|
+
Keep the root auth surface session-first. Only wire the JWT plugin when the host app explicitly needs token-based flows:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { provideHttpClient } from '@angular/common/http';
|
|
132
|
+
import { withJwtAuthHttpInterceptors } from '@anarchitects/auth-angular/data-access/jwt';
|
|
133
|
+
import { provideAuthJwtState } from '@anarchitects/auth-angular/state/jwt';
|
|
134
|
+
|
|
135
|
+
export const appConfig: ApplicationConfig = {
|
|
136
|
+
providers: [
|
|
137
|
+
provideHttpClient(withJwtAuthHttpInterceptors()),
|
|
138
|
+
...provideAuthJwtState(),
|
|
139
|
+
],
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
125
143
|
Blog ownership example:
|
|
126
144
|
|
|
127
145
|
```ts
|
|
@@ -172,12 +190,16 @@ export class PostActionsComponent {
|
|
|
172
190
|
|
|
173
191
|
| Import path | Description |
|
|
174
192
|
| ---------------------------------------- | --------------------------------------- |
|
|
175
|
-
| `@anarchitects/auth-angular/config`
|
|
176
|
-
| `@anarchitects/auth-angular/data-access`
|
|
177
|
-
| `@anarchitects/auth-angular/
|
|
178
|
-
| `@anarchitects/auth-angular/
|
|
179
|
-
| `@anarchitects/auth-angular/
|
|
180
|
-
| `@anarchitects/auth-angular/
|
|
193
|
+
| `@anarchitects/auth-angular/config` | DI tokens and providers |
|
|
194
|
+
| `@anarchitects/auth-angular/data-access` | Generated API clients and HTTP adapters |
|
|
195
|
+
| `@anarchitects/auth-angular/data-access/jwt` | JWT plugin APIs and interceptor helpers |
|
|
196
|
+
| `@anarchitects/auth-angular/state` | Signal store, eager restore, CASL ability sync |
|
|
197
|
+
| `@anarchitects/auth-angular/state/jwt` | JWT refresh-token state orchestration |
|
|
198
|
+
| `@anarchitects/auth-angular/feature` | Coarse and resource-aware router guards |
|
|
199
|
+
| `@anarchitects/auth-angular/feature/jwt` | JWT refresh-token orchestration components |
|
|
200
|
+
| `@anarchitects/auth-angular/ui` | Auth domain form UI components |
|
|
201
|
+
| `@anarchitects/auth-angular/ui/jwt` | JWT refresh-token form components |
|
|
202
|
+
| `@anarchitects/auth-angular/util` | CASL ability/resource helpers and typings |
|
|
181
203
|
|
|
182
204
|
## Nx scripts
|
|
183
205
|
|
|
@@ -189,9 +211,11 @@ export class PostActionsComponent {
|
|
|
189
211
|
|
|
190
212
|
- DTOs live in `@anarchitects/auth-ts`; regenerate OpenAPI docs when route schemas change (`nx run api-specs:generate`).
|
|
191
213
|
- Data-access layer should always use the generated OpenAPI clients—no manual HTTP calls.
|
|
192
|
-
- State layer uses Angular signals via `@ngrx/signals` for reactive updates, hydrates raw RBAC rules plus the derived CASL ability, and restores sessions eagerly when provided.
|
|
214
|
+
- State layer uses Angular signals via `@ngrx/signals` for reactive updates, hydrates raw RBAC rules plus the derived CASL ability, and restores Better Auth-backed sessions eagerly when provided.
|
|
193
215
|
- `AuthStore.initialized()` and `AuthStore.restoring()` let apps avoid auth flicker while bootstrap restore completes.
|
|
194
216
|
- `/auth/me` RBAC payloads are parsed at the frontend trust boundary; malformed authorization data fails closed instead of producing a partially trusted ability.
|
|
217
|
+
- Core root surfaces are session-first. JWT plugin helpers live under layer-scoped subpaths such as `@anarchitects/auth-angular/data-access/jwt`, `@anarchitects/auth-angular/state/jwt`, `@anarchitects/auth-angular/feature/jwt`, and `@anarchitects/auth-angular/ui/jwt`.
|
|
218
|
+
- Feature components must orchestrate through state entrypoints; they should not call data-access entrypoints directly.
|
|
195
219
|
- Ability creation and concrete resource checks are centralised in `@anarchitects/auth-angular/util`; import the helpers instead of instantiating CASL directly.
|
|
196
220
|
- `policyGuard` is coarse by design; use `resourcePolicyGuard` and backend instance checks for ownership-sensitive routes.
|
|
197
221
|
- Keep UI, feature, data-access, state, and config layers decoupled per architecture guidelines.
|
package/data-access/README.md
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
# @anarchitects/auth-angular/data-access
|
|
2
2
|
|
|
3
|
-
HTTP adapters that bridge Angular apps to the auth Nest API using the OpenAPI-generated DTOs. Import from `@anarchitects/auth-angular/data-access`
|
|
3
|
+
HTTP adapters that bridge Angular apps to the auth Nest API using the OpenAPI-generated DTOs. Import from `@anarchitects/auth-angular/data-access` for the session-first core auth surface.
|
|
4
4
|
|
|
5
5
|
## Exports
|
|
6
6
|
|
|
7
7
|
- `AuthApi`: injectable service backed by Angular `HttpClient`
|
|
8
|
-
- `authBearerTokenInterceptor`: adds `Authorization: Bearer <accessToken>` when an access token is stored
|
|
9
|
-
- `authErrorInterceptor`: handles `401/403`, attempts token refresh, retries request, and redirects to login on terminal auth failure
|
|
10
|
-
- `withAuthHttpInterceptors()`: convenience helper for `provideHttpClient(...)`
|
|
11
8
|
- Uses configuration from `@anarchitects/auth-angular/config` to resolve the `/api/{resource}` path
|
|
12
|
-
- Methods map
|
|
9
|
+
- Methods map to the core session-oriented auth surface (`registerUser`, `login`, `logout`, `getLoggedInUserInfo`, etc.)
|
|
10
|
+
- JWT plugin helpers live under `@anarchitects/auth-angular/data-access/jwt`
|
|
13
11
|
|
|
14
12
|
## Usage
|
|
15
13
|
|
|
@@ -30,15 +28,15 @@ export class AuthFacade {
|
|
|
30
28
|
|
|
31
29
|
Prefer consuming `AuthApi` from orchestrating feature services or signal stores so UI components remain presentation-only.
|
|
32
30
|
|
|
33
|
-
##
|
|
31
|
+
## JWT plugin usage
|
|
34
32
|
|
|
35
33
|
```ts
|
|
36
34
|
import { ApplicationConfig } from '@angular/core';
|
|
37
35
|
import { provideHttpClient } from '@angular/common/http';
|
|
38
|
-
import {
|
|
36
|
+
import { withJwtAuthHttpInterceptors } from '@anarchitects/auth-angular/data-access/jwt';
|
|
39
37
|
|
|
40
38
|
export const appConfig: ApplicationConfig = {
|
|
41
|
-
providers: [provideHttpClient(
|
|
39
|
+
providers: [provideHttpClient(withJwtAuthHttpInterceptors())],
|
|
42
40
|
};
|
|
43
41
|
```
|
|
44
42
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# @anarchitects/auth-angular/data-access/jwt
|
|
2
|
+
|
|
3
|
+
JWT plugin-specific data-access helpers for `@anarchitects/auth-angular`.
|
|
4
|
+
|
|
5
|
+
Use this entrypoint only when the JWT plugin is enabled on the Nest side. The root `@anarchitects/auth-angular/data-access` surface remains session-first and should be the default for core auth flows.
|
|
6
|
+
|
|
7
|
+
## Exports
|
|
8
|
+
|
|
9
|
+
- `JwtAuthApi`: HTTP adapter for `/auth/jwt/login`, `/auth/jwt/logout`, and `/auth/jwt/refresh`
|
|
10
|
+
- `withJwtAuthHttpInterceptors()`: interceptor helpers for JWT token injection and refresh behavior
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { provideHttpClient } from '@angular/common/http';
|
|
16
|
+
import { withJwtAuthHttpInterceptors } from '@anarchitects/auth-angular/data-access/jwt';
|
|
17
|
+
|
|
18
|
+
export const appConfig = {
|
|
19
|
+
providers: [provideHttpClient(withJwtAuthHttpInterceptors())],
|
|
20
|
+
};
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Keep JWT orchestration in the JWT state layer. Feature code should depend on `@anarchitects/auth-angular/state/jwt`, not call `JwtAuthApi` directly.
|
package/feature/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @anarchitects/auth-angular/feature
|
|
2
2
|
|
|
3
|
-
Feature-level orchestration for Angular auth. It ships route guards plus standalone feature components that orchestrate auth actions via
|
|
3
|
+
Feature-level orchestration for Angular auth. It ships route guards plus standalone feature components that orchestrate auth actions via state-layer entrypoints and delegate rendering to `@anarchitects/auth-angular/ui`.
|
|
4
|
+
|
|
5
|
+
JWT-specific feature components live under `@anarchitects/auth-angular/feature/jwt`, not the root feature entry point. They should orchestrate through `@anarchitects/auth-angular/state/jwt`, never `data-access/jwt` directly.
|
|
4
6
|
|
|
5
7
|
## Exports
|
|
6
8
|
|
|
@@ -15,7 +17,6 @@ Feature-level orchestration for Angular auth. It ships route guards plus standal
|
|
|
15
17
|
- `AnarchitectsFeatureChangePassword`
|
|
16
18
|
- `AnarchitectsFeatureUpdateEmail`
|
|
17
19
|
- `AnarchitectsFeatureLogout`
|
|
18
|
-
- `AnarchitectsFeatureRefreshTokens`
|
|
19
20
|
|
|
20
21
|
## Usage
|
|
21
22
|
|
|
@@ -63,6 +64,8 @@ Do not treat `policyGuard` as a full `PolicyRule` mirror. It is intentionally co
|
|
|
63
64
|
|
|
64
65
|
Ensure the state layer is explicitly provided in your app/route providers by wiring `...provideAuthState()` from `@anarchitects/auth-angular/state`.
|
|
65
66
|
|
|
67
|
+
JWT plugin feature flows should likewise register `...provideAuthJwtState()` from `@anarchitects/auth-angular/state/jwt` when the route/page mounts JWT-specific components.
|
|
68
|
+
|
|
66
69
|
### Token-driven actions
|
|
67
70
|
|
|
68
71
|
```ts
|
|
@@ -99,13 +102,12 @@ export class ChangePasswordPageComponent {
|
|
|
99
102
|
|
|
100
103
|
```ts
|
|
101
104
|
import { Component } from '@angular/core';
|
|
102
|
-
import {
|
|
105
|
+
import { AnarchitectsFeatureLogout } from '@anarchitects/auth-angular/feature';
|
|
103
106
|
|
|
104
107
|
@Component({
|
|
105
108
|
selector: 'app-session-page',
|
|
106
|
-
imports: [
|
|
109
|
+
imports: [AnarchitectsFeatureLogout],
|
|
107
110
|
template: `
|
|
108
|
-
<anarchitects-auth-feature-refresh-tokens [userId]="userId" />
|
|
109
111
|
<anarchitects-auth-feature-logout />
|
|
110
112
|
`,
|
|
111
113
|
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @anarchitects/auth-angular/feature/jwt
|
|
2
|
+
|
|
3
|
+
JWT plugin-specific feature orchestration for `@anarchitects/auth-angular`.
|
|
4
|
+
|
|
5
|
+
Use this entrypoint only when the JWT plugin is enabled. It sits on top of `@anarchitects/auth-angular/state/jwt` and delegates rendering to `@anarchitects/auth-angular/ui/jwt`.
|
|
6
|
+
|
|
7
|
+
## Exports
|
|
8
|
+
|
|
9
|
+
- `AnarchitectsAuthJwtRefreshTokens`
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Component } from '@angular/core';
|
|
15
|
+
import { provideAuthJwtState } from '@anarchitects/auth-angular/state/jwt';
|
|
16
|
+
import { AnarchitectsAuthJwtRefreshTokens } from '@anarchitects/auth-angular/feature/jwt';
|
|
17
|
+
|
|
18
|
+
@Component({
|
|
19
|
+
selector: 'app-refresh-page',
|
|
20
|
+
imports: [AnarchitectsAuthJwtRefreshTokens],
|
|
21
|
+
providers: [...provideAuthJwtState()],
|
|
22
|
+
template: `<anarchitects-auth-jwt-refresh-tokens />`,
|
|
23
|
+
})
|
|
24
|
+
export class RefreshPageComponent {}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Keep feature orchestration on the state layer. Do not import `data-access/jwt` directly into feature code.
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { HttpContextToken } from '@angular/common/http';
|
|
1
2
|
import { InjectionToken, inject } from '@angular/core';
|
|
2
3
|
|
|
3
4
|
const AUTH_CONFIG = new InjectionToken('AUTH_CONFIG');
|
|
4
5
|
const API_RESOURCE_PATH = new InjectionToken('AUTH_API_RESOURCE_PATH');
|
|
6
|
+
const SUPPRESS_AUTH_FAILURE_REDIRECT = new HttpContextToken(() => false);
|
|
5
7
|
/** Library-level sensible defaults */
|
|
6
8
|
const AUTH_DEFAULTS = {
|
|
7
9
|
apiResourcePath: 'auth',
|
|
10
|
+
plugins: {
|
|
11
|
+
jwt: {
|
|
12
|
+
enabled: false,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
8
15
|
};
|
|
9
16
|
/** Safe injectors that fall back to defaults if no providers are registered */
|
|
10
17
|
function injectAuthConfig() {
|
|
@@ -16,7 +23,18 @@ function injectApiResourcePath() {
|
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
function provideAuthConfig(cfg) {
|
|
19
|
-
const merged = {
|
|
26
|
+
const merged = {
|
|
27
|
+
...AUTH_DEFAULTS,
|
|
28
|
+
...cfg,
|
|
29
|
+
plugins: {
|
|
30
|
+
...AUTH_DEFAULTS.plugins,
|
|
31
|
+
...cfg.plugins,
|
|
32
|
+
jwt: {
|
|
33
|
+
...AUTH_DEFAULTS.plugins.jwt,
|
|
34
|
+
...cfg.plugins?.jwt,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
20
38
|
return [
|
|
21
39
|
{ provide: AUTH_CONFIG, useValue: merged },
|
|
22
40
|
{ provide: API_RESOURCE_PATH, useValue: merged.apiResourcePath },
|
|
@@ -30,5 +48,5 @@ function provideAuthDefaults() {
|
|
|
30
48
|
* Generated bundle index. Do not edit.
|
|
31
49
|
*/
|
|
32
50
|
|
|
33
|
-
export { API_RESOURCE_PATH, AUTH_CONFIG, AUTH_DEFAULTS, injectApiResourcePath, injectAuthConfig, provideAuthConfig, provideAuthDefaults };
|
|
51
|
+
export { API_RESOURCE_PATH, AUTH_CONFIG, AUTH_DEFAULTS, SUPPRESS_AUTH_FAILURE_REDIRECT, injectApiResourcePath, injectAuthConfig, provideAuthConfig, provideAuthDefaults };
|
|
34
52
|
//# sourceMappingURL=anarchitects-auth-angular-config.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anarchitects-auth-angular-config.mjs","sources":["../../../../../libs/auth/angular/config/src/tokens.ts","../../../../../libs/auth/angular/config/src/providers.ts","../../../../../libs/auth/angular/config/src/anarchitects-auth-angular-config.ts"],"sourcesContent":["import { InjectionToken, inject } from '@angular/core';\n\nexport type AuthConfig = {\n apiResourcePath: string;\n};\n\nexport const AUTH_CONFIG = new InjectionToken<AuthConfig>('AUTH_CONFIG');\nexport const API_RESOURCE_PATH = new InjectionToken<string>(\n 'AUTH_API_RESOURCE_PATH'\n);\n\n/** Library-level sensible defaults */\nexport const AUTH_DEFAULTS: AuthConfig = {\n apiResourcePath: 'auth',\n};\n\n/** Safe injectors that fall back to defaults if no providers are registered */\nexport function injectAuthConfig(): AuthConfig {\n return inject(AUTH_CONFIG, { optional: true }) ?? AUTH_DEFAULTS;\n}\n\nexport function injectApiResourcePath(): string {\n return (\n inject(API_RESOURCE_PATH, { optional: true }) ??\n AUTH_DEFAULTS.apiResourcePath\n );\n}\n","import { Provider } from '@angular/core';\nimport {\n API_RESOURCE_PATH,\n AUTH_CONFIG,\n AUTH_DEFAULTS,\n AuthConfig,\n} from './tokens';\n\nexport function provideAuthConfig(cfg: Partial<AuthConfig>): Provider[] {\n const merged: AuthConfig = { ...AUTH_DEFAULTS
|
|
1
|
+
{"version":3,"file":"anarchitects-auth-angular-config.mjs","sources":["../../../../../libs/auth/angular/config/src/tokens.ts","../../../../../libs/auth/angular/config/src/providers.ts","../../../../../libs/auth/angular/config/src/anarchitects-auth-angular-config.ts"],"sourcesContent":["import { HttpContextToken } from '@angular/common/http';\nimport { InjectionToken, inject } from '@angular/core';\n\nexport type AuthConfig = {\n apiResourcePath: string;\n plugins: {\n jwt: {\n enabled: boolean;\n };\n };\n};\n\nexport const AUTH_CONFIG = new InjectionToken<AuthConfig>('AUTH_CONFIG');\nexport const API_RESOURCE_PATH = new InjectionToken<string>(\n 'AUTH_API_RESOURCE_PATH'\n);\nexport const SUPPRESS_AUTH_FAILURE_REDIRECT = new HttpContextToken<boolean>(\n () => false,\n);\n\n/** Library-level sensible defaults */\nexport const AUTH_DEFAULTS: AuthConfig = {\n apiResourcePath: 'auth',\n plugins: {\n jwt: {\n enabled: false,\n },\n },\n};\n\n/** Safe injectors that fall back to defaults if no providers are registered */\nexport function injectAuthConfig(): AuthConfig {\n return inject(AUTH_CONFIG, { optional: true }) ?? AUTH_DEFAULTS;\n}\n\nexport function injectApiResourcePath(): string {\n return (\n inject(API_RESOURCE_PATH, { optional: true }) ??\n AUTH_DEFAULTS.apiResourcePath\n );\n}\n","import { Provider } from '@angular/core';\nimport {\n API_RESOURCE_PATH,\n AUTH_CONFIG,\n AUTH_DEFAULTS,\n AuthConfig,\n} from './tokens';\n\nexport function provideAuthConfig(cfg: Partial<AuthConfig>): Provider[] {\n const merged: AuthConfig = {\n ...AUTH_DEFAULTS,\n ...cfg,\n plugins: {\n ...AUTH_DEFAULTS.plugins,\n ...cfg.plugins,\n jwt: {\n ...AUTH_DEFAULTS.plugins.jwt,\n ...cfg.plugins?.jwt,\n },\n },\n };\n return [\n { provide: AUTH_CONFIG, useValue: merged },\n { provide: API_RESOURCE_PATH, useValue: merged.apiResourcePath },\n ];\n}\n\nexport function provideAuthDefaults(): Provider[] {\n return provideAuthConfig({});\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;MAYa,WAAW,GAAG,IAAI,cAAc,CAAa,aAAa;MAC1D,iBAAiB,GAAG,IAAI,cAAc,CACjD,wBAAwB;AAEnB,MAAM,8BAA8B,GAAG,IAAI,gBAAgB,CAChE,MAAM,KAAK;AAGb;AACO,MAAM,aAAa,GAAe;AACvC,IAAA,eAAe,EAAE,MAAM;AACvB,IAAA,OAAO,EAAE;AACP,QAAA,GAAG,EAAE;AACH,YAAA,OAAO,EAAE,KAAK;AACf,SAAA;AACF,KAAA;;AAGH;SACgB,gBAAgB,GAAA;AAC9B,IAAA,OAAO,MAAM,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,aAAa;AACjE;SAEgB,qBAAqB,GAAA;IACnC,QACE,MAAM,CAAC,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAC7C,aAAa,CAAC,eAAe;AAEjC;;AChCM,SAAU,iBAAiB,CAAC,GAAwB,EAAA;AACxD,IAAA,MAAM,MAAM,GAAe;AACzB,QAAA,GAAG,aAAa;AAChB,QAAA,GAAG,GAAG;AACN,QAAA,OAAO,EAAE;YACP,GAAG,aAAa,CAAC,OAAO;YACxB,GAAG,GAAG,CAAC,OAAO;AACd,YAAA,GAAG,EAAE;AACH,gBAAA,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG;AAC5B,gBAAA,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG;AACpB,aAAA;AACF,SAAA;KACF;IACD,OAAO;AACL,QAAA,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE;QAC1C,EAAE,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,CAAC,eAAe,EAAE;KACjE;AACH;SAEgB,mBAAmB,GAAA;AACjC,IAAA,OAAO,iBAAiB,CAAC,EAAE,CAAC;AAC9B;;AC7BA;;AAEG;;;;"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { injectApiResourcePath, injectAuthConfig, SUPPRESS_AUTH_FAILURE_REDIRECT } from '@anarchitects/auth-angular/config';
|
|
2
|
+
import { HttpClient, HttpContextToken, HttpErrorResponse, HttpStatusCode, HttpBackend, withInterceptors } from '@angular/common/http';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { inject, Injectable } from '@angular/core';
|
|
5
|
+
import { jwtDecode } from 'jwt-decode';
|
|
6
|
+
import { Router } from '@angular/router';
|
|
7
|
+
import { tap, finalize, shareReplay, catchError, throwError, switchMap } from 'rxjs';
|
|
8
|
+
|
|
9
|
+
class JwtAuthApi {
|
|
10
|
+
http = inject(HttpClient);
|
|
11
|
+
resourceUrl = `/api/${injectApiResourcePath()}`;
|
|
12
|
+
login(dto) {
|
|
13
|
+
return this.http.post(`${this.resourceUrl}/jwt/login`, dto);
|
|
14
|
+
}
|
|
15
|
+
logout(dto) {
|
|
16
|
+
return this.http.post(`${this.resourceUrl}/jwt/logout`, dto);
|
|
17
|
+
}
|
|
18
|
+
refreshTokens(dto) {
|
|
19
|
+
return this.http.post(`${this.resourceUrl}/jwt/refresh`, dto);
|
|
20
|
+
}
|
|
21
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: JwtAuthApi, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
22
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: JwtAuthApi, providedIn: 'root' });
|
|
23
|
+
}
|
|
24
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: JwtAuthApi, decorators: [{
|
|
25
|
+
type: Injectable,
|
|
26
|
+
args: [{
|
|
27
|
+
providedIn: 'root',
|
|
28
|
+
}]
|
|
29
|
+
}] });
|
|
30
|
+
|
|
31
|
+
const ACCESS_TOKEN_STORAGE_KEY = 'accessToken';
|
|
32
|
+
const REFRESH_TOKEN_STORAGE_KEY = 'refreshToken';
|
|
33
|
+
function getStoredToken(key) {
|
|
34
|
+
try {
|
|
35
|
+
if (typeof localStorage === 'undefined') {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
return localStorage.getItem(key) ?? undefined;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function storeTokens(tokens) {
|
|
45
|
+
try {
|
|
46
|
+
if (typeof localStorage === 'undefined') {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
localStorage.setItem(ACCESS_TOKEN_STORAGE_KEY, tokens.accessToken);
|
|
50
|
+
localStorage.setItem(REFRESH_TOKEN_STORAGE_KEY, tokens.refreshToken);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// noop: storage can be unavailable in non-browser environments
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function clearStoredTokens() {
|
|
57
|
+
try {
|
|
58
|
+
if (typeof localStorage === 'undefined') {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
localStorage.removeItem(ACCESS_TOKEN_STORAGE_KEY);
|
|
62
|
+
localStorage.removeItem(REFRESH_TOKEN_STORAGE_KEY);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// noop: storage can be unavailable in non-browser environments
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function resolveUserIdFromAccessToken(accessToken) {
|
|
69
|
+
if (!accessToken) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const decoded = jwtDecode(accessToken);
|
|
74
|
+
return decoded.sub;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const authBearerTokenInterceptor = (req, next) => {
|
|
82
|
+
const authConfig = injectAuthConfig();
|
|
83
|
+
if (!authConfig.plugins.jwt.enabled) {
|
|
84
|
+
return next(req);
|
|
85
|
+
}
|
|
86
|
+
const accessToken = getStoredToken(ACCESS_TOKEN_STORAGE_KEY);
|
|
87
|
+
if (!accessToken || req.headers.has('Authorization')) {
|
|
88
|
+
return next(req);
|
|
89
|
+
}
|
|
90
|
+
return next(req.clone({
|
|
91
|
+
setHeaders: {
|
|
92
|
+
Authorization: `Bearer ${accessToken}`,
|
|
93
|
+
},
|
|
94
|
+
}));
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const AUTH_RETRY_ATTEMPTED = new HttpContextToken(() => false);
|
|
98
|
+
const LOGIN_REDIRECT_PATH = '/login';
|
|
99
|
+
let refreshTokensRequest$ = null;
|
|
100
|
+
function isUnauthorizedError(error) {
|
|
101
|
+
return (error instanceof HttpErrorResponse &&
|
|
102
|
+
(error.status === HttpStatusCode.Unauthorized ||
|
|
103
|
+
error.status === HttpStatusCode.Forbidden));
|
|
104
|
+
}
|
|
105
|
+
function isAuthPublicEndpoint(url, authBaseUrl) {
|
|
106
|
+
const publicEndpoints = [
|
|
107
|
+
'/login',
|
|
108
|
+
'/register',
|
|
109
|
+
'/activate',
|
|
110
|
+
'/forgot-password',
|
|
111
|
+
'/reset-password',
|
|
112
|
+
'/verify-email',
|
|
113
|
+
];
|
|
114
|
+
return publicEndpoints.some((endpoint) => url.includes(`${authBaseUrl}${endpoint}`));
|
|
115
|
+
}
|
|
116
|
+
function isRefreshEndpoint(url, authBaseUrl) {
|
|
117
|
+
return url.includes(`${authBaseUrl}/jwt/refresh`);
|
|
118
|
+
}
|
|
119
|
+
function redirectToLogin(router) {
|
|
120
|
+
if (router) {
|
|
121
|
+
void router.navigateByUrl(LOGIN_REDIRECT_PATH);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (typeof window !== 'undefined') {
|
|
125
|
+
window.location.assign(LOGIN_REDIRECT_PATH);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function shouldRedirectToLogin(req) {
|
|
129
|
+
return !req.context.get(SUPPRESS_AUTH_FAILURE_REDIRECT);
|
|
130
|
+
}
|
|
131
|
+
function getRefreshTokensRequest(http, refreshUrl, refreshToken) {
|
|
132
|
+
if (!refreshTokensRequest$) {
|
|
133
|
+
refreshTokensRequest$ = http
|
|
134
|
+
.post(refreshUrl, { refreshToken })
|
|
135
|
+
.pipe(tap((tokens) => storeTokens(tokens)), finalize(() => {
|
|
136
|
+
refreshTokensRequest$ = null;
|
|
137
|
+
}), shareReplay(1));
|
|
138
|
+
}
|
|
139
|
+
return refreshTokensRequest$;
|
|
140
|
+
}
|
|
141
|
+
const authErrorInterceptor = (req, next) => {
|
|
142
|
+
const authBaseUrl = `/api/${injectApiResourcePath()}`;
|
|
143
|
+
const backend = inject(HttpBackend);
|
|
144
|
+
const router = inject(Router, { optional: true });
|
|
145
|
+
const rawHttp = new HttpClient(backend);
|
|
146
|
+
return next(req).pipe(catchError((error) => {
|
|
147
|
+
if (!isUnauthorizedError(error)) {
|
|
148
|
+
return throwError(() => error);
|
|
149
|
+
}
|
|
150
|
+
if (req.context.get(AUTH_RETRY_ATTEMPTED) ||
|
|
151
|
+
isRefreshEndpoint(req.url, authBaseUrl) ||
|
|
152
|
+
isAuthPublicEndpoint(req.url, authBaseUrl)) {
|
|
153
|
+
if (req.context.get(AUTH_RETRY_ATTEMPTED)) {
|
|
154
|
+
clearStoredTokens();
|
|
155
|
+
if (shouldRedirectToLogin(req)) {
|
|
156
|
+
redirectToLogin(router ?? null);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return throwError(() => error);
|
|
160
|
+
}
|
|
161
|
+
const refreshToken = getStoredToken(REFRESH_TOKEN_STORAGE_KEY);
|
|
162
|
+
if (!refreshToken) {
|
|
163
|
+
clearStoredTokens();
|
|
164
|
+
if (shouldRedirectToLogin(req)) {
|
|
165
|
+
redirectToLogin(router ?? null);
|
|
166
|
+
}
|
|
167
|
+
return throwError(() => error);
|
|
168
|
+
}
|
|
169
|
+
const refreshUrl = `${authBaseUrl}/jwt/refresh`;
|
|
170
|
+
return getRefreshTokensRequest(rawHttp, refreshUrl, refreshToken).pipe(switchMap(({ accessToken: nextAccessToken }) => {
|
|
171
|
+
const retryRequest = req.clone({
|
|
172
|
+
context: req.context.set(AUTH_RETRY_ATTEMPTED, true),
|
|
173
|
+
setHeaders: {
|
|
174
|
+
Authorization: `Bearer ${nextAccessToken}`,
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
return next(retryRequest);
|
|
178
|
+
}), catchError((refreshError) => {
|
|
179
|
+
clearStoredTokens();
|
|
180
|
+
if (shouldRedirectToLogin(req)) {
|
|
181
|
+
redirectToLogin(router ?? null);
|
|
182
|
+
}
|
|
183
|
+
return throwError(() => refreshError);
|
|
184
|
+
}));
|
|
185
|
+
}));
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const JWT_AUTH_HTTP_INTERCEPTORS = [
|
|
189
|
+
authBearerTokenInterceptor,
|
|
190
|
+
authErrorInterceptor,
|
|
191
|
+
];
|
|
192
|
+
function withJwtAuthHttpInterceptors() {
|
|
193
|
+
return withInterceptors(JWT_AUTH_HTTP_INTERCEPTORS);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Generated bundle index. Do not edit.
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
export { ACCESS_TOKEN_STORAGE_KEY, JWT_AUTH_HTTP_INTERCEPTORS, JwtAuthApi, REFRESH_TOKEN_STORAGE_KEY, authBearerTokenInterceptor, authErrorInterceptor, clearStoredTokens, getStoredToken, resolveUserIdFromAccessToken, storeTokens, withJwtAuthHttpInterceptors };
|
|
201
|
+
//# sourceMappingURL=anarchitects-auth-angular-data-access-jwt.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anarchitects-auth-angular-data-access-jwt.mjs","sources":["../../../../../libs/auth/angular/data-access/jwt/src/jwt-auth-api.ts","../../../../../libs/auth/angular/data-access/jwt/src/interceptors/auth-token.utils.ts","../../../../../libs/auth/angular/data-access/jwt/src/interceptors/bearer-token.interceptor.ts","../../../../../libs/auth/angular/data-access/jwt/src/interceptors/auth-error.interceptor.ts","../../../../../libs/auth/angular/data-access/jwt/src/interceptors/index.ts","../../../../../libs/auth/angular/data-access/jwt/src/anarchitects-auth-angular-data-access-jwt.ts"],"sourcesContent":["import { injectApiResourcePath } from '@anarchitects/auth-angular/config';\nimport { LoginRequestDTO } from '@anarchitects/auth-ts/dtos';\nimport {\n JwtLogoutRequestDTO,\n LoginResponseDTO,\n RefreshTokenRequestDTO,\n RefreshTokenResponseDTO,\n} from '@anarchitects/auth-ts/dtos/jwt';\nimport { HttpClient } from '@angular/common/http';\nimport { inject, Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class JwtAuthApi {\n private readonly http = inject(HttpClient);\n private readonly resourceUrl = `/api/${injectApiResourcePath()}`;\n\n login(dto: LoginRequestDTO) {\n return this.http.post<LoginResponseDTO>(`${this.resourceUrl}/jwt/login`, dto);\n }\n\n logout(dto: JwtLogoutRequestDTO) {\n return this.http.post<{ success: boolean }>(\n `${this.resourceUrl}/jwt/logout`,\n dto,\n );\n }\n\n refreshTokens(dto: RefreshTokenRequestDTO) {\n return this.http.post<RefreshTokenResponseDTO>(\n `${this.resourceUrl}/jwt/refresh`,\n dto,\n );\n }\n}\n","import { jwtDecode } from 'jwt-decode';\n\nexport const ACCESS_TOKEN_STORAGE_KEY = 'accessToken';\nexport const REFRESH_TOKEN_STORAGE_KEY = 'refreshToken';\n\nexport type LoginTokens = {\n accessToken: string;\n refreshToken: string;\n};\n\nexport function getStoredToken(key: string): string | undefined {\n try {\n if (typeof localStorage === 'undefined') {\n return undefined;\n }\n\n return localStorage.getItem(key) ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function storeTokens(tokens: LoginTokens): void {\n try {\n if (typeof localStorage === 'undefined') {\n return;\n }\n\n localStorage.setItem(ACCESS_TOKEN_STORAGE_KEY, tokens.accessToken);\n localStorage.setItem(REFRESH_TOKEN_STORAGE_KEY, tokens.refreshToken);\n } catch {\n // noop: storage can be unavailable in non-browser environments\n }\n}\n\nexport function clearStoredTokens(): void {\n try {\n if (typeof localStorage === 'undefined') {\n return;\n }\n\n localStorage.removeItem(ACCESS_TOKEN_STORAGE_KEY);\n localStorage.removeItem(REFRESH_TOKEN_STORAGE_KEY);\n } catch {\n // noop: storage can be unavailable in non-browser environments\n }\n}\n\nexport function resolveUserIdFromAccessToken(\n accessToken: string | undefined\n): string | undefined {\n if (!accessToken) {\n return undefined;\n }\n\n try {\n const decoded = jwtDecode<{ sub?: string }>(accessToken);\n return decoded.sub;\n } catch {\n return undefined;\n }\n}\n","import { injectAuthConfig } from '@anarchitects/auth-angular/config';\nimport { HttpInterceptorFn } from '@angular/common/http';\nimport { ACCESS_TOKEN_STORAGE_KEY, getStoredToken } from './auth-token.utils';\n\nexport const authBearerTokenInterceptor: HttpInterceptorFn = (req, next) => {\n const authConfig = injectAuthConfig();\n if (!authConfig.plugins.jwt.enabled) {\n return next(req);\n }\n\n const accessToken = getStoredToken(ACCESS_TOKEN_STORAGE_KEY);\n\n if (!accessToken || req.headers.has('Authorization')) {\n return next(req);\n }\n\n return next(\n req.clone({\n setHeaders: {\n Authorization: `Bearer ${accessToken}`,\n },\n })\n );\n};\n","import {\n HttpBackend,\n HttpClient,\n HttpContextToken,\n HttpErrorResponse,\n HttpInterceptorFn,\n HttpStatusCode,\n} from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport {\n injectApiResourcePath,\n SUPPRESS_AUTH_FAILURE_REDIRECT,\n} from '@anarchitects/auth-angular/config';\nimport { LoginResponseDTO } from '@anarchitects/auth-ts/dtos/jwt';\nimport { Router } from '@angular/router';\nimport {\n catchError,\n finalize,\n Observable,\n shareReplay,\n switchMap,\n tap,\n throwError,\n} from 'rxjs';\nimport {\n REFRESH_TOKEN_STORAGE_KEY,\n clearStoredTokens,\n getStoredToken,\n storeTokens,\n} from './auth-token.utils';\n\nconst AUTH_RETRY_ATTEMPTED = new HttpContextToken<boolean>(() => false);\nconst LOGIN_REDIRECT_PATH = '/login';\n\nlet refreshTokensRequest$: Observable<LoginResponseDTO> | null = null;\n\nfunction isUnauthorizedError(error: unknown): error is HttpErrorResponse {\n return (\n error instanceof HttpErrorResponse &&\n (error.status === HttpStatusCode.Unauthorized ||\n error.status === HttpStatusCode.Forbidden)\n );\n}\n\nfunction isAuthPublicEndpoint(url: string, authBaseUrl: string): boolean {\n const publicEndpoints = [\n '/login',\n '/register',\n '/activate',\n '/forgot-password',\n '/reset-password',\n '/verify-email',\n ];\n\n return publicEndpoints.some((endpoint) =>\n url.includes(`${authBaseUrl}${endpoint}`)\n );\n}\n\nfunction isRefreshEndpoint(url: string, authBaseUrl: string): boolean {\n return url.includes(`${authBaseUrl}/jwt/refresh`);\n}\n\nfunction redirectToLogin(router: Router | null): void {\n if (router) {\n void router.navigateByUrl(LOGIN_REDIRECT_PATH);\n return;\n }\n\n if (typeof window !== 'undefined') {\n window.location.assign(LOGIN_REDIRECT_PATH);\n }\n}\n\nfunction shouldRedirectToLogin(req: Parameters<HttpInterceptorFn>[0]): boolean {\n return !req.context.get(SUPPRESS_AUTH_FAILURE_REDIRECT);\n}\n\nfunction getRefreshTokensRequest(\n http: HttpClient,\n refreshUrl: string,\n refreshToken: string\n): Observable<LoginResponseDTO> {\n if (!refreshTokensRequest$) {\n refreshTokensRequest$ = http\n .post<LoginResponseDTO>(refreshUrl, { refreshToken })\n .pipe(\n tap((tokens) => storeTokens(tokens)),\n finalize(() => {\n refreshTokensRequest$ = null;\n }),\n shareReplay(1)\n );\n }\n\n return refreshTokensRequest$;\n}\n\nexport const authErrorInterceptor: HttpInterceptorFn = (req, next) => {\n const authBaseUrl = `/api/${injectApiResourcePath()}`;\n const backend = inject(HttpBackend);\n const router = inject(Router, { optional: true });\n const rawHttp = new HttpClient(backend);\n\n return next(req).pipe(\n catchError((error) => {\n if (!isUnauthorizedError(error)) {\n return throwError(() => error);\n }\n\n if (\n req.context.get(AUTH_RETRY_ATTEMPTED) ||\n isRefreshEndpoint(req.url, authBaseUrl) ||\n isAuthPublicEndpoint(req.url, authBaseUrl)\n ) {\n if (req.context.get(AUTH_RETRY_ATTEMPTED)) {\n clearStoredTokens();\n if (shouldRedirectToLogin(req)) {\n redirectToLogin(router ?? null);\n }\n }\n\n return throwError(() => error);\n }\n\n const refreshToken = getStoredToken(REFRESH_TOKEN_STORAGE_KEY);\n if (!refreshToken) {\n clearStoredTokens();\n if (shouldRedirectToLogin(req)) {\n redirectToLogin(router ?? null);\n }\n return throwError(() => error);\n }\n\n const refreshUrl = `${authBaseUrl}/jwt/refresh`;\n\n return getRefreshTokensRequest(rawHttp, refreshUrl, refreshToken).pipe(\n switchMap(({ accessToken: nextAccessToken }) => {\n const retryRequest = req.clone({\n context: req.context.set(AUTH_RETRY_ATTEMPTED, true),\n setHeaders: {\n Authorization: `Bearer ${nextAccessToken}`,\n },\n });\n\n return next(retryRequest);\n }),\n catchError((refreshError) => {\n clearStoredTokens();\n if (shouldRedirectToLogin(req)) {\n redirectToLogin(router ?? null);\n }\n return throwError(() => refreshError);\n })\n );\n })\n );\n};\n","import { HttpInterceptorFn, withInterceptors } from '@angular/common/http';\nimport { authBearerTokenInterceptor } from './bearer-token.interceptor';\nimport { authErrorInterceptor } from './auth-error.interceptor';\n\nexport const JWT_AUTH_HTTP_INTERCEPTORS: HttpInterceptorFn[] = [\n authBearerTokenInterceptor,\n authErrorInterceptor,\n];\n\nexport function withJwtAuthHttpInterceptors() {\n return withInterceptors(JWT_AUTH_HTTP_INTERCEPTORS);\n}\n\nexport * from './bearer-token.interceptor';\nexport * from './auth-error.interceptor';\nexport * from './auth-token.utils';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|