@nauth-toolkit/client-angular 0.1.58 → 0.1.59
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/esm2022/lib/auth.guard.mjs +58 -23
- package/esm2022/lib/social-redirect-callback.guard.mjs +28 -24
- package/esm2022/ngmodule/auth.service.mjs +16 -1
- package/esm2022/ngmodule/nauth.module.mjs +4 -1
- package/esm2022/standalone/auth.guard.mjs +32 -13
- package/esm2022/standalone/auth.service.mjs +16 -1
- package/esm2022/standalone/social-redirect-callback.guard.mjs +28 -24
- package/fesm2022/nauth-toolkit-client-angular-standalone.mjs +70 -34
- package/fesm2022/nauth-toolkit-client-angular-standalone.mjs.map +1 -1
- package/fesm2022/nauth-toolkit-client-angular.mjs +157 -103
- package/fesm2022/nauth-toolkit-client-angular.mjs.map +1 -1
- package/lib/auth.guard.d.ts +39 -16
- package/lib/social-redirect-callback.guard.d.ts +2 -2
- package/ngmodule/auth.service.d.ts +13 -0
- package/package.json +2 -2
- package/standalone/auth.guard.d.ts +13 -6
- package/standalone/auth.service.d.ts +13 -0
- package/standalone/social-redirect-callback.guard.d.ts +2 -2
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { NAuthErrorCode, NAuthClientError, NAuthClient } from '@nauth-toolkit/client';
|
|
2
2
|
export * from '@nauth-toolkit/client';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { InjectionToken, Injectable, Inject,
|
|
4
|
+
import { InjectionToken, Injectable, Inject, inject, Optional, NgModule, PLATFORM_ID } from '@angular/core';
|
|
5
5
|
import { firstValueFrom, BehaviorSubject, Subject, catchError, from, switchMap, throwError, filter as filter$1, take } from 'rxjs';
|
|
6
6
|
import { filter } from 'rxjs/operators';
|
|
7
7
|
import * as i1 from '@angular/common/http';
|
|
8
8
|
import { HttpErrorResponse, HTTP_INTERCEPTORS, HttpClientModule, HttpClient } from '@angular/common/http';
|
|
9
9
|
import * as i3 from '@angular/router';
|
|
10
10
|
import { Router } from '@angular/router';
|
|
11
|
+
import { __decorate, __param } from 'tslib';
|
|
11
12
|
import { isPlatformBrowser } from '@angular/common';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -266,6 +267,21 @@ class AuthService {
|
|
|
266
267
|
getCurrentChallenge() {
|
|
267
268
|
return this.challengeSubject.value;
|
|
268
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Get challenge router for manual navigation control.
|
|
272
|
+
* Useful for guards that need to handle errors or build custom URLs.
|
|
273
|
+
*
|
|
274
|
+
* @returns ChallengeRouter instance
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* const router = this.auth.getChallengeRouter();
|
|
279
|
+
* await router.navigateToError('oauth');
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
getChallengeRouter() {
|
|
283
|
+
return this.client.getChallengeRouter();
|
|
284
|
+
}
|
|
269
285
|
// ============================================================================
|
|
270
286
|
// Core Auth Methods
|
|
271
287
|
// ============================================================================
|
|
@@ -1008,6 +1024,118 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1008
1024
|
args: [NAUTH_CLIENT_CONFIG]
|
|
1009
1025
|
}] }, { type: i1.HttpClient }, { type: AuthService }, { type: i3.Router }] });
|
|
1010
1026
|
|
|
1027
|
+
/**
|
|
1028
|
+
* Functional route guard for authentication (Angular 17+).
|
|
1029
|
+
*
|
|
1030
|
+
* Protects routes by checking if user is authenticated.
|
|
1031
|
+
* Redirects to configured session expired route (or login) if not authenticated.
|
|
1032
|
+
*
|
|
1033
|
+
* @param redirectTo - Optional path to redirect to if not authenticated. If not provided, uses `redirects.sessionExpired` from config (defaults to '/login')
|
|
1034
|
+
* @returns CanActivateFn guard function
|
|
1035
|
+
*
|
|
1036
|
+
* @example
|
|
1037
|
+
* ```typescript
|
|
1038
|
+
* // In route configuration - uses config.redirects.sessionExpired
|
|
1039
|
+
* const routes: Routes = [
|
|
1040
|
+
* {
|
|
1041
|
+
* path: 'home',
|
|
1042
|
+
* component: HomeComponent,
|
|
1043
|
+
* canActivate: [authGuard()]
|
|
1044
|
+
* }
|
|
1045
|
+
* ];
|
|
1046
|
+
*
|
|
1047
|
+
* // Override with custom route
|
|
1048
|
+
* const routes: Routes = [
|
|
1049
|
+
* {
|
|
1050
|
+
* path: 'admin',
|
|
1051
|
+
* component: AdminComponent,
|
|
1052
|
+
* canActivate: [authGuard('/admin/login')]
|
|
1053
|
+
* }
|
|
1054
|
+
* ];
|
|
1055
|
+
* ```
|
|
1056
|
+
*/
|
|
1057
|
+
function authGuard(redirectTo) {
|
|
1058
|
+
return () => {
|
|
1059
|
+
const auth = inject(AuthService);
|
|
1060
|
+
const router = inject(Router);
|
|
1061
|
+
const config = inject(NAUTH_CLIENT_CONFIG, { optional: true });
|
|
1062
|
+
if (auth.isAuthenticated()) {
|
|
1063
|
+
return true;
|
|
1064
|
+
}
|
|
1065
|
+
// Use provided redirectTo, or config.redirects.sessionExpired, or default to '/login'
|
|
1066
|
+
const redirectPath = redirectTo ?? config?.redirects?.sessionExpired ?? '/login';
|
|
1067
|
+
return router.createUrlTree([redirectPath]);
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Class-based authentication guard for NgModule compatibility.
|
|
1072
|
+
*
|
|
1073
|
+
* **Note:** When using `NAuthModule.forRoot()`, `AuthGuard` is automatically provided
|
|
1074
|
+
* and has access to the configuration. You don't need to add it to your module's providers.
|
|
1075
|
+
*
|
|
1076
|
+
* @example
|
|
1077
|
+
* ```typescript
|
|
1078
|
+
* // app.module.ts - AuthGuard is automatically provided by NAuthModule.forRoot()
|
|
1079
|
+
* @NgModule({
|
|
1080
|
+
* imports: [
|
|
1081
|
+
* NAuthModule.forRoot({
|
|
1082
|
+
* baseUrl: 'https://api.example.com/auth',
|
|
1083
|
+
* tokenDelivery: 'cookies',
|
|
1084
|
+
* redirects: {
|
|
1085
|
+
* sessionExpired: '/login?expired=true',
|
|
1086
|
+
* },
|
|
1087
|
+
* }),
|
|
1088
|
+
* RouterModule.forRoot([
|
|
1089
|
+
* {
|
|
1090
|
+
* path: 'home',
|
|
1091
|
+
* component: HomeComponent,
|
|
1092
|
+
* canActivate: [AuthGuard], // Uses config.redirects.sessionExpired
|
|
1093
|
+
* },
|
|
1094
|
+
* ]),
|
|
1095
|
+
* ],
|
|
1096
|
+
* })
|
|
1097
|
+
* export class AppModule {}
|
|
1098
|
+
*
|
|
1099
|
+
* // Or provide manually in a feature module (still has access to root config)
|
|
1100
|
+
* @NgModule({
|
|
1101
|
+
* providers: [AuthGuard],
|
|
1102
|
+
* })
|
|
1103
|
+
* export class FeatureModule {}
|
|
1104
|
+
* ```
|
|
1105
|
+
*/
|
|
1106
|
+
let AuthGuard = class AuthGuard {
|
|
1107
|
+
auth;
|
|
1108
|
+
router;
|
|
1109
|
+
config;
|
|
1110
|
+
/**
|
|
1111
|
+
* @param auth - Authentication service
|
|
1112
|
+
* @param router - Angular router
|
|
1113
|
+
* @param config - Optional client configuration (injected automatically)
|
|
1114
|
+
*/
|
|
1115
|
+
constructor(auth, router, config) {
|
|
1116
|
+
this.auth = auth;
|
|
1117
|
+
this.router = router;
|
|
1118
|
+
this.config = config;
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Check if route can be activated.
|
|
1122
|
+
*
|
|
1123
|
+
* @returns True if authenticated, otherwise redirects to configured session expired route (or '/login')
|
|
1124
|
+
*/
|
|
1125
|
+
canActivate() {
|
|
1126
|
+
if (this.auth.isAuthenticated()) {
|
|
1127
|
+
return true;
|
|
1128
|
+
}
|
|
1129
|
+
// Use config.redirects.sessionExpired or default to '/login'
|
|
1130
|
+
const redirectPath = this.config?.redirects?.sessionExpired ?? '/login';
|
|
1131
|
+
return this.router.createUrlTree([redirectPath]);
|
|
1132
|
+
}
|
|
1133
|
+
};
|
|
1134
|
+
AuthGuard = __decorate([
|
|
1135
|
+
__param(2, Optional()),
|
|
1136
|
+
__param(2, Inject(NAUTH_CLIENT_CONFIG))
|
|
1137
|
+
], AuthGuard);
|
|
1138
|
+
|
|
1011
1139
|
/**
|
|
1012
1140
|
* NgModule for nauth-toolkit Angular integration.
|
|
1013
1141
|
*
|
|
@@ -1051,6 +1179,8 @@ class NAuthModule {
|
|
|
1051
1179
|
useClass: AuthInterceptorClass,
|
|
1052
1180
|
multi: true,
|
|
1053
1181
|
},
|
|
1182
|
+
// Provide AuthGuard so it has access to NAUTH_CLIENT_CONFIG
|
|
1183
|
+
AuthGuard,
|
|
1054
1184
|
],
|
|
1055
1185
|
};
|
|
1056
1186
|
}
|
|
@@ -1217,86 +1347,6 @@ class AuthInterceptor {
|
|
|
1217
1347
|
}
|
|
1218
1348
|
}
|
|
1219
1349
|
|
|
1220
|
-
/**
|
|
1221
|
-
* Functional route guard for authentication (Angular 17+).
|
|
1222
|
-
*
|
|
1223
|
-
* Protects routes by checking if user is authenticated.
|
|
1224
|
-
* Redirects to login page if not authenticated.
|
|
1225
|
-
*
|
|
1226
|
-
* @param redirectTo - Path to redirect to if not authenticated (default: '/login')
|
|
1227
|
-
* @returns CanActivateFn guard function
|
|
1228
|
-
*
|
|
1229
|
-
* @example
|
|
1230
|
-
* ```typescript
|
|
1231
|
-
* // In route configuration
|
|
1232
|
-
* const routes: Routes = [
|
|
1233
|
-
* {
|
|
1234
|
-
* path: 'home',
|
|
1235
|
-
* component: HomeComponent,
|
|
1236
|
-
* canActivate: [authGuard()]
|
|
1237
|
-
* },
|
|
1238
|
-
* {
|
|
1239
|
-
* path: 'admin',
|
|
1240
|
-
* component: AdminComponent,
|
|
1241
|
-
* canActivate: [authGuard('/admin/login')]
|
|
1242
|
-
* }
|
|
1243
|
-
* ];
|
|
1244
|
-
* ```
|
|
1245
|
-
*/
|
|
1246
|
-
function authGuard(redirectTo = '/login') {
|
|
1247
|
-
return () => {
|
|
1248
|
-
const auth = inject(AuthService);
|
|
1249
|
-
const router = inject(Router);
|
|
1250
|
-
if (auth.isAuthenticated()) {
|
|
1251
|
-
return true;
|
|
1252
|
-
}
|
|
1253
|
-
return router.createUrlTree([redirectTo]);
|
|
1254
|
-
};
|
|
1255
|
-
}
|
|
1256
|
-
/**
|
|
1257
|
-
* Class-based authentication guard for NgModule compatibility.
|
|
1258
|
-
*
|
|
1259
|
-
* @example
|
|
1260
|
-
* ```typescript
|
|
1261
|
-
* // In route configuration (NgModule)
|
|
1262
|
-
* const routes: Routes = [
|
|
1263
|
-
* {
|
|
1264
|
-
* path: 'home',
|
|
1265
|
-
* component: HomeComponent,
|
|
1266
|
-
* canActivate: [AuthGuard]
|
|
1267
|
-
* }
|
|
1268
|
-
* ];
|
|
1269
|
-
*
|
|
1270
|
-
* // In module providers
|
|
1271
|
-
* @NgModule({
|
|
1272
|
-
* providers: [AuthGuard]
|
|
1273
|
-
* })
|
|
1274
|
-
* ```
|
|
1275
|
-
*/
|
|
1276
|
-
class AuthGuard {
|
|
1277
|
-
auth;
|
|
1278
|
-
router;
|
|
1279
|
-
/**
|
|
1280
|
-
* @param auth - Authentication service
|
|
1281
|
-
* @param router - Angular router
|
|
1282
|
-
*/
|
|
1283
|
-
constructor(auth, router) {
|
|
1284
|
-
this.auth = auth;
|
|
1285
|
-
this.router = router;
|
|
1286
|
-
}
|
|
1287
|
-
/**
|
|
1288
|
-
* Check if route can be activated.
|
|
1289
|
-
*
|
|
1290
|
-
* @returns True if authenticated, otherwise redirects to login
|
|
1291
|
-
*/
|
|
1292
|
-
canActivate() {
|
|
1293
|
-
if (this.auth.isAuthenticated()) {
|
|
1294
|
-
return true;
|
|
1295
|
-
}
|
|
1296
|
-
return this.router.createUrlTree(['/login']);
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
1350
|
/**
|
|
1301
1351
|
* Social redirect callback route guard.
|
|
1302
1352
|
*
|
|
@@ -1307,8 +1357,8 @@ class AuthGuard {
|
|
|
1307
1357
|
* - `error` / `error_description` (provider errors)
|
|
1308
1358
|
*
|
|
1309
1359
|
* Behavior:
|
|
1310
|
-
* - If `exchangeToken` exists: exchanges it via backend
|
|
1311
|
-
* - If no `exchangeToken`: treat as cookie-success path
|
|
1360
|
+
* - If `exchangeToken` exists: exchanges it via backend (SDK handles navigation automatically).
|
|
1361
|
+
* - If no `exchangeToken`: treat as cookie-success path (SDK handles navigation automatically).
|
|
1312
1362
|
* - If `error` exists: redirects to oauthError route.
|
|
1313
1363
|
*
|
|
1314
1364
|
* @example
|
|
@@ -1322,7 +1372,6 @@ class AuthGuard {
|
|
|
1322
1372
|
*/
|
|
1323
1373
|
const socialRedirectCallbackGuard = async () => {
|
|
1324
1374
|
const auth = inject(AuthService);
|
|
1325
|
-
const config = inject(NAUTH_CLIENT_CONFIG);
|
|
1326
1375
|
const platformId = inject(PLATFORM_ID);
|
|
1327
1376
|
const isBrowser = isPlatformBrowser(platformId);
|
|
1328
1377
|
if (!isBrowser) {
|
|
@@ -1331,13 +1380,13 @@ const socialRedirectCallbackGuard = async () => {
|
|
|
1331
1380
|
const params = new URLSearchParams(window.location.search);
|
|
1332
1381
|
const error = params.get('error');
|
|
1333
1382
|
const exchangeToken = params.get('exchangeToken');
|
|
1383
|
+
const router = auth.getChallengeRouter();
|
|
1334
1384
|
// Provider error: redirect to oauthError
|
|
1335
1385
|
if (error) {
|
|
1336
|
-
|
|
1337
|
-
window.location.replace(errorUrl);
|
|
1386
|
+
await router.navigateToError('oauth');
|
|
1338
1387
|
return false;
|
|
1339
1388
|
}
|
|
1340
|
-
// No exchangeToken: cookie success path;
|
|
1389
|
+
// No exchangeToken: cookie success path; hydrate then navigate to success.
|
|
1341
1390
|
//
|
|
1342
1391
|
// Note: we do not "activate" the callback route to avoid consumers needing to render a page.
|
|
1343
1392
|
if (!exchangeToken) {
|
|
@@ -1351,26 +1400,31 @@ const socialRedirectCallbackGuard = async () => {
|
|
|
1351
1400
|
// `currentUser` is still null even though cookies were set successfully.
|
|
1352
1401
|
try {
|
|
1353
1402
|
await auth.getProfile();
|
|
1403
|
+
await router.navigateToSuccess();
|
|
1354
1404
|
}
|
|
1355
|
-
catch {
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1405
|
+
catch (err) {
|
|
1406
|
+
// Only treat auth failures (401/403) as OAuth errors
|
|
1407
|
+
// Network errors or other issues might be temporary - still try success route
|
|
1408
|
+
const isAuthError = err instanceof NAuthClientError &&
|
|
1409
|
+
(err.statusCode === 401 ||
|
|
1410
|
+
err.statusCode === 403 ||
|
|
1411
|
+
err.code === NAuthErrorCode.AUTH_TOKEN_INVALID ||
|
|
1412
|
+
err.code === NAuthErrorCode.AUTH_SESSION_EXPIRED ||
|
|
1413
|
+
err.code === NAuthErrorCode.AUTH_SESSION_NOT_FOUND);
|
|
1414
|
+
if (isAuthError) {
|
|
1415
|
+
// Cookies weren't set properly - OAuth failed
|
|
1416
|
+
await router.navigateToError('oauth');
|
|
1417
|
+
}
|
|
1418
|
+
else {
|
|
1419
|
+
// For network errors or other issues, proceed to success route
|
|
1420
|
+
// The auth guard will handle authentication state on the next route
|
|
1421
|
+
await router.navigateToSuccess();
|
|
1422
|
+
}
|
|
1359
1423
|
}
|
|
1360
|
-
const successUrl = config.redirects?.success || '/';
|
|
1361
|
-
window.location.replace(successUrl);
|
|
1362
|
-
return false;
|
|
1363
|
-
}
|
|
1364
|
-
// Exchange token and route accordingly
|
|
1365
|
-
const response = await auth.exchangeSocialRedirect(exchangeToken);
|
|
1366
|
-
if (response.challengeName) {
|
|
1367
|
-
const challengeBase = config.redirects?.challengeBase || '/auth/challenge';
|
|
1368
|
-
const challengeRoute = response.challengeName.toLowerCase().replace(/_/g, '-');
|
|
1369
|
-
window.location.replace(`${challengeBase}/${challengeRoute}`);
|
|
1370
1424
|
return false;
|
|
1371
1425
|
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1426
|
+
// Exchange token - SDK handles navigation automatically
|
|
1427
|
+
await auth.exchangeSocialRedirect(exchangeToken);
|
|
1374
1428
|
return false;
|
|
1375
1429
|
};
|
|
1376
1430
|
|