@nauth-toolkit/client-angular 0.1.53 → 0.1.55
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 +4 -177
- package/ng-package.json +12 -0
- package/package.json +22 -18
- package/src/lib/auth.guard.ts +86 -0
- package/src/lib/auth.interceptor.ts +194 -0
- package/src/lib/social-redirect-callback.guard.ts +87 -0
- package/src/ngmodule/auth.interceptor.class.ts +124 -0
- package/src/ngmodule/auth.service.ts +865 -0
- package/src/ngmodule/http-adapter.ts +79 -0
- package/src/ngmodule/nauth.module.ts +59 -0
- package/src/ngmodule/tokens.ts +7 -0
- package/src/package.json +11 -0
- package/src/public-api.ts +21 -0
- package/src/standalone/ng-package.json +7 -0
- package/src/standalone/package.json +8 -0
- package/src/standalone/public-api.ts +12 -0
- package/standalone/auth.guard.ts +86 -0
- package/standalone/auth.interceptor.ts +194 -0
- package/standalone/auth.service.ts +865 -0
- package/standalone/http-adapter.ts +79 -0
- package/standalone/ng-package.json +7 -0
- package/standalone/package.json +8 -0
- package/standalone/public-api.ts +18 -0
- package/standalone/social-redirect-callback.guard.ts +87 -0
- package/standalone/tokens.ts +7 -0
- package/tsconfig.json +10 -0
- package/tsconfig.lib.json +28 -0
- package/tsconfig.lib.prod.json +10 -0
- package/fesm2022/nauth-toolkit-client-angular.mjs +0 -1211
- package/fesm2022/nauth-toolkit-client-angular.mjs.map +0 -1
- package/types/nauth-toolkit-client-angular.d.ts +0 -747
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Injectable, Inject } from '@angular/core';
|
|
2
|
+
import {
|
|
3
|
+
HttpInterceptor,
|
|
4
|
+
HttpRequest,
|
|
5
|
+
HttpHandler,
|
|
6
|
+
HttpEvent,
|
|
7
|
+
HttpClient,
|
|
8
|
+
HttpErrorResponse,
|
|
9
|
+
} from '@angular/common/http';
|
|
10
|
+
import { Router } from '@angular/router';
|
|
11
|
+
import { Observable, catchError, switchMap, throwError, filter, take, BehaviorSubject, from } from 'rxjs';
|
|
12
|
+
import { NAUTH_CLIENT_CONFIG } from './tokens';
|
|
13
|
+
import { AuthService } from './auth.service';
|
|
14
|
+
import { NAuthClientConfig } from '@nauth-toolkit/client';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Refresh state management.
|
|
18
|
+
*/
|
|
19
|
+
let isRefreshing = false;
|
|
20
|
+
const refreshTokenSubject = new BehaviorSubject<string | null>(null);
|
|
21
|
+
const retriedRequests = new WeakSet<HttpRequest<unknown>>();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get CSRF token from cookie.
|
|
25
|
+
*/
|
|
26
|
+
function getCsrfToken(cookieName: string): string | null {
|
|
27
|
+
if (typeof document === 'undefined') return null;
|
|
28
|
+
const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));
|
|
29
|
+
return match ? decodeURIComponent(match[2]) : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Class-based HTTP interceptor for NgModule apps (Angular < 17).
|
|
34
|
+
*
|
|
35
|
+
* For standalone components (Angular 17+), use the functional `authInterceptor` instead.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // app.module.ts
|
|
40
|
+
* import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
41
|
+
* import { AuthInterceptor } from '@nauth-toolkit/client-angular';
|
|
42
|
+
*
|
|
43
|
+
* @NgModule({
|
|
44
|
+
* providers: [
|
|
45
|
+
* { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
|
|
46
|
+
* ]
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
@Injectable()
|
|
51
|
+
export class AuthInterceptor implements HttpInterceptor {
|
|
52
|
+
constructor(
|
|
53
|
+
@Inject(NAUTH_CLIENT_CONFIG) private readonly config: NAuthClientConfig,
|
|
54
|
+
private readonly http: HttpClient,
|
|
55
|
+
private readonly authService: AuthService,
|
|
56
|
+
private readonly router: Router,
|
|
57
|
+
) {}
|
|
58
|
+
|
|
59
|
+
intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
|
60
|
+
const tokenDelivery = this.config.tokenDelivery;
|
|
61
|
+
const baseUrl = this.config.baseUrl;
|
|
62
|
+
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// COOKIES MODE: withCredentials + CSRF token
|
|
65
|
+
// ============================================================================
|
|
66
|
+
if (tokenDelivery === 'cookies') {
|
|
67
|
+
let clonedReq = req.clone({ withCredentials: true });
|
|
68
|
+
|
|
69
|
+
// Add CSRF token header if it's a mutating request
|
|
70
|
+
if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {
|
|
71
|
+
const csrfToken = getCsrfToken(this.config.csrf?.cookieName || 'XSRF-TOKEN');
|
|
72
|
+
if (csrfToken) {
|
|
73
|
+
clonedReq = clonedReq.clone({
|
|
74
|
+
setHeaders: { [this.config.csrf?.headerName || 'X-XSRF-TOKEN']: csrfToken },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return next.handle(clonedReq).pipe(
|
|
80
|
+
catchError((error: HttpErrorResponse) => {
|
|
81
|
+
if (error.status === 401 && !retriedRequests.has(req)) {
|
|
82
|
+
retriedRequests.add(req);
|
|
83
|
+
|
|
84
|
+
if (!isRefreshing) {
|
|
85
|
+
isRefreshing = true;
|
|
86
|
+
refreshTokenSubject.next(null);
|
|
87
|
+
|
|
88
|
+
return from(
|
|
89
|
+
this.http
|
|
90
|
+
.post<{ accessToken?: string }>(`${baseUrl}/refresh`, {}, { withCredentials: true })
|
|
91
|
+
.toPromise(),
|
|
92
|
+
).pipe(
|
|
93
|
+
switchMap(() => {
|
|
94
|
+
isRefreshing = false;
|
|
95
|
+
refreshTokenSubject.next('refreshed');
|
|
96
|
+
return next.handle(clonedReq);
|
|
97
|
+
}),
|
|
98
|
+
catchError((refreshError) => {
|
|
99
|
+
isRefreshing = false;
|
|
100
|
+
this.authService.logout();
|
|
101
|
+
this.router.navigate([this.config.redirects?.sessionExpired || '/login']);
|
|
102
|
+
return throwError(() => refreshError);
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
} else {
|
|
106
|
+
return refreshTokenSubject.pipe(
|
|
107
|
+
filter((token) => token !== null),
|
|
108
|
+
take(1),
|
|
109
|
+
switchMap(() => next.handle(clonedReq)),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return throwError(() => error);
|
|
115
|
+
}),
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ============================================================================
|
|
120
|
+
// JSON MODE: Delegate to SDK for token handling
|
|
121
|
+
// ============================================================================
|
|
122
|
+
return next.handle(req);
|
|
123
|
+
}
|
|
124
|
+
}
|