Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@christianacca/angular-swa-auth

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@christianacca/angular-swa-auth - npm Package Compare versions

Comparing version 1.1.2 to 2.0.0-beta.1

124

bundles/christianacca-angular-swa-auth.umd.js

@@ -567,3 +567,8 @@ (function (global, factory) {

*/
var hasSomeAllowedRoles = function (allowedRoles, actualRoles) { return allowedRoles.length === 0 || allowedRoles.includes(anonymousRole) || allowedRoles.some(function (r) { return actualRoles.includes(r); }); };
var hasSomeAllowedRoles = function (allowedRoles, actualRoles) {
var allowedRoleNames = allowedRoles.flat(10);
return (allowedRoleNames.length === 0 ||
allowedRoleNames.includes(anonymousRole) ||
allowedRoleNames.some(function (r) { return actualRoles.includes(r); }));
};
/**

@@ -588,3 +593,3 @@ * The main service for working with authenticated users

this.sessionEvents$ = this.sessionEvents.asObservable();
this.userLoaded$ = rxjs.defer(function () { return _this.httpGet('/.auth/me'); }).pipe(operators.map(function (resp) { return resp.clientPrincipal; }), operators.tap(function (user) {
this.currentUser$ = rxjs.defer(function () { return _this.httpGet('/.auth/me'); }).pipe(operators.map(function (resp) { return resp.clientPrincipal; }), operators.tap(function (user) {
if (user) {

@@ -594,4 +599,4 @@ _this.publishAuthenticatedSuccessEvents(user);

}), operators.shareReplay({ bufferSize: 1, refCount: false }));
this.isAuthenticated$ = this.userLoaded$.pipe(operators.map(function (user) { return !!user; }), operators.shareReplay({ bufferSize: 1, refCount: false }));
this.currentIdp$ = this.userLoaded$.pipe(operators.map(function (user) { return user === null || user === void 0 ? void 0 : user.identityProvider; }));
this.isAuthenticated$ = this.currentUser$.pipe(operators.map(function (user) { return !!user; }), operators.shareReplay({ bufferSize: 1, refCount: false }));
this.currentIdp$ = this.currentUser$.pipe(operators.map(function (user) { return user === null || user === void 0 ? void 0 : user.identityProvider; }));
}

@@ -613,3 +618,3 @@ /**

switch (_b.label) {
case 0: return [4 /*yield*/, this.userLoaded$.pipe(operators.first()).toPromise()];
case 0: return [4 /*yield*/, this.currentUser$.pipe(operators.first()).toPromise()];
case 1:

@@ -629,7 +634,11 @@ user = _b.sent();

/**
* Does the current user have one or more of the `allowedRoles` supplied
* Does the current user have one or more of the `allowedRoles` supplied.
*
* Note: because the observable returned completes, consumers do NOT have to unsubscribe from it
*
* @param allowedRoles The list of roles to check
* @return {Observable<boolean>} an observable that returns true/false and then completes
*/
AuthService.prototype.hasSomeRoles$ = function (allowedRoles) {
return this.userLoaded$.pipe(operators.map(function (user) { var _a; return hasSomeAllowedRoles(allowedRoles, (_a = user === null || user === void 0 ? void 0 : user.userRoles) !== null && _a !== void 0 ? _a : noExplicitRoles$1); }));
return this.currentUser$.pipe(operators.map(function (user) { var _a; return hasSomeAllowedRoles(allowedRoles, (_a = user === null || user === void 0 ? void 0 : user.userRoles) !== null && _a !== void 0 ? _a : noExplicitRoles$1); }), operators.take(1));
};

@@ -682,3 +691,3 @@ /**

switch (_b.label) {
case 0: return [4 /*yield*/, this.userLoaded$.toPromise()];
case 0: return [4 /*yield*/, this.currentUser$.toPromise()];
case 1:

@@ -710,3 +719,3 @@ user = _b.sent();

switch (_b.label) {
case 0: return [4 /*yield*/, this.userLoaded$.toPromise()];
case 0: return [4 /*yield*/, this.currentUser$.toPromise()];
case 1:

@@ -894,8 +903,8 @@ user = _b.sent();

* ```html
* <nav class="menu" *swaRoleCheck="let isAdmin of ['admin']; let maybeAdmin = isPlaceholder">
* <nav class="menu" *swaRoleCheck="let canAdmin of ['admin']; let maybeCanAdmin = isPlaceholder">
* <p class="menu-label">Menu</p>
* <ul class="menu-list">
* <a routerLink="/users" routerLinkActive="is-active">
* <progress *ngIf="maybeAdmin" class="progress is-primary is-medium" max="100">15%</progress>
* <span *ngIf="!maybeAdmin" [ngClass]="!isAdmin ? 'has-text-grey-lighter' : ''">Users</span>
* <progress *ngIf="maybeCanAdmin" class="progress is-primary is-medium" max="100">15%</progress>
* <span *ngIf="!maybeCanAdmin" [ngClass]="!canAdmin ? 'has-text-grey-lighter' : ''">Users</span>
* </a>

@@ -946,3 +955,3 @@ * </ul>

var _this = this;
var injectedRoles$ = this.authService.userLoaded$.pipe(operators.map(function (user) { return user === null || user === void 0 ? void 0 : user.userRoles; }), operators.takeUntil(this.userRolesFromTemplate));
var injectedRoles$ = this.authService.currentUser$.pipe(operators.map(function (user) { return user === null || user === void 0 ? void 0 : user.userRoles; }), operators.takeUntil(this.userRolesFromTemplate));
var userRoles$ = rxjs.merge(this.userRolesFromTemplate, injectedRoles$).pipe(operators.map(function (x) { return x !== null && x !== void 0 ? x : noExplicitRoles; }));

@@ -1029,10 +1038,14 @@ var permissionCheck$ = rxjs.combineLatest([this.allowedRoles, userRoles$]).pipe(operators.map(function (_a) {

*
* Implements `CanActivate` to ensure the user is authenticated before allowing the navigation to the route.
* Where the user is not yet authenticated, trigger the login flow.
* @see { AuthService.ensureLoggedIn}
* Implements `CanLoad` for use with lazy loaded routes and `CanActivate` for regular routes.
*
* @see { AuthService.ensureLoggedIn }
* @example
* ```ts
* export const routes: Routes = [
* { path: '', pathMatch: 'full', redirectTo: 'secure-page' },
* { path: 'secure-page', component: SecurePageComponent, canActivate: [AuthGuard] }
* { path: 'secure-page', component: SecurePageComponent, canActivate: [AuthGuard] },
* {
* path: 'product',
* canLoad: [AuthGuard],
* loadChildren: () => import('@christianacca/demo-app/product-admin').then(m => m.ProductAdminModule)
* },
* ];

@@ -1042,4 +1055,5 @@ * ```

var AuthGuard = /** @class */ (function () {
function AuthGuard(authService) {
function AuthGuard(authService, router) {
this.authService = authService;
this.router = router;
}

@@ -1049,5 +1063,10 @@ AuthGuard.prototype.canActivate = function (_route, state) {

};
AuthGuard.prototype.canLoad = function ( /* route: Route, segments: UrlSegment[] */) {
var navigation = this.router.getCurrentNavigation();
var targetUrl = !navigation ? '/' : navigation.extractedUrl.toString();
return this.authService.ensureLoggedIn(targetUrl);
};
return AuthGuard;
}());
AuthGuard.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AuthGuard, deps: [{ token: AuthService }], target: i0__namespace.ɵɵFactoryTarget.Injectable });
AuthGuard.ɵfac = i0__namespace.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AuthGuard, deps: [{ token: AuthService }, { token: i2__namespace.Router }], target: i0__namespace.ɵɵFactoryTarget.Injectable });
AuthGuard.ɵprov = i0__namespace.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AuthGuard, providedIn: 'root' });

@@ -1059,3 +1078,3 @@ i0__namespace.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0__namespace, type: AuthGuard, decorators: [{

}]
}], ctorParameters: function () { return [{ type: AuthService }]; } });
}], ctorParameters: function () { return [{ type: AuthService }, { type: i2__namespace.Router }]; } });

@@ -1065,8 +1084,13 @@ /**

*
* Implements `CanActivate` to verify that the current user is a member of one or more roles
* as defined in an `allowedRoles` field on `Route.data` for the route about to be navigated to
* Implements `CanLoad` for use with lazy loaded routes and `CanActivate` for regular routes.
*
* Will first trigger the sign in flow when the user is not already authenticated. Then verifies
* that the user is a member of one or more {@link AllowedRole}'s as defined in an `allowedRoles`
* field on `Route.data` for the route about to be navigated to.
*
* Where the user is deemed unauthorized the SPA will be routed to the client-side route configured
* using {@link AuthConfig.unauthorizedRoute}
*
* @see {AuthService.hasSomeRoles$}
*
* @example

@@ -1076,8 +1100,16 @@ * ```ts

* {
* path: 'admin-page',
* path: 'product-admin',
* data: {
* allowedRoles: 'admin' // or ['admin',]
* allowedRoles: 'admin' // other ex: ['admin', 'owner'] ['admin', ['product-reader', 'owner']]
* },
* canActivate: [SwaRoleGuard],
* component: AdminComponent
* },
* {
* path: 'user-admin',
* data: {
* allowedRoles: 'owner'
* },
* canLoad: [SwaRoleGuard],
* loadChildren: () => import('@christianacca/demo-app/user-admin').then(m => m.UserAdminModule)
* }

@@ -1093,11 +1125,43 @@ * ];

}
SwaRoleGuard.prototype.canActivate = function (route) {
SwaRoleGuard.getAllowedRoles = function (route) {
var _a;
var roles = (_a = route.data) === null || _a === void 0 ? void 0 : _a.allowedRoles;
if (!roles) {
return undefined;
}
return Array.isArray(roles) ? roles : [roles];
};
SwaRoleGuard.prototype.canActivate = function (route, state) {
return this.ensureHasRouteRoles(route, state.url);
};
SwaRoleGuard.prototype.canLoad = function (route) {
var navigation = this.router.getCurrentNavigation();
var targetUrl = !navigation ? '/' : navigation.extractedUrl.toString();
return this.ensureHasRouteRoles(route, targetUrl);
};
SwaRoleGuard.prototype.ensureHasRouteRoles = function (route, targetUrl) {
var _this = this;
var roles = route.data['allowedRoles'];
if (!roles) {
// Q: why are we calling `ensureLoggedIn` below?
// A: Angular will execute CanLoad guards BEFORE CanActivate guards
// Therefore this guard runs BEFORE the AuthGuard. As a consequence, this guard also
// needs to trigger the login flow.
var allowedRoles = SwaRoleGuard.getAllowedRoles(route);
if (!allowedRoles) {
return true;
}
var allowedRoles = Array.isArray(roles) ? roles : [roles];
return this.authService.hasSomeRoles$(allowedRoles).pipe(operators.map(function (isAuthorized) { return isAuthorized || _this.router.parseUrl(_this.config.unauthorizedRoute); }), operators.take(1));
var isLoggedIn$ = rxjs.from(this.authService.ensureLoggedIn(targetUrl));
return isLoggedIn$.pipe(operators.switchMap(function (isLoggedIn) {
if (!isLoggedIn) {
// the user cancelled login prompt
return rxjs.of(false);
}
return _this.ensureHasSomeRoles(allowedRoles);
}));
};
SwaRoleGuard.prototype.ensureHasSomeRoles = function (allowedRoles) {
var _this = this;
return this.authService
.hasSomeRoles$(allowedRoles)
.pipe(operators.map(function (isAuthorized) { return isAuthorized || _this.router.parseUrl(_this.config.unauthorizedRoute); }));
};
return SwaRoleGuard;

@@ -1104,0 +1168,0 @@ }());

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './auth.service';
import * as i0 from "@angular/core";
import * as i1 from "./auth.service";
import * as i2 from "@angular/router";
/**
* Add to a route to trigger the sign in flow when the user is not already authenticated
*
* Implements `CanActivate` to ensure the user is authenticated before allowing the navigation to the route.
* Where the user is not yet authenticated, trigger the login flow.
* @see { AuthService.ensureLoggedIn}
* Implements `CanLoad` for use with lazy loaded routes and `CanActivate` for regular routes.
*
* @see { AuthService.ensureLoggedIn }
* @example
* ```ts
* export const routes: Routes = [
* { path: '', pathMatch: 'full', redirectTo: 'secure-page' },
* { path: 'secure-page', component: SecurePageComponent, canActivate: [AuthGuard] }
* { path: 'secure-page', component: SecurePageComponent, canActivate: [AuthGuard] },
* {
* path: 'product',
* canLoad: [AuthGuard],
* loadChildren: () => import('@christianacca/demo-app/product-admin').then(m => m.ProductAdminModule)
* },
* ];

@@ -20,4 +26,5 @@ * ```

export class AuthGuard {
constructor(authService) {
constructor(authService, router) {
this.authService = authService;
this.router = router;
}

@@ -27,4 +34,9 @@ canActivate(_route, state) {

}
canLoad( /* route: Route, segments: UrlSegment[] */) {
const navigation = this.router.getCurrentNavigation();
const targetUrl = !navigation ? '/' : navigation.extractedUrl.toString();
return this.authService.ensureLoggedIn(targetUrl);
}
}
AuthGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AuthGuard, deps: [{ token: i1.AuthService }], target: i0.ɵɵFactoryTarget.Injectable });
AuthGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AuthGuard, deps: [{ token: i1.AuthService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
AuthGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AuthGuard, providedIn: 'root' });

@@ -36,3 +48,3 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AuthGuard, decorators: [{

}]
}], ctorParameters: function () { return [{ type: i1.AuthService }]; } });
}], ctorParameters: function () { return [{ type: i1.AuthService }, { type: i2.Router }]; } });
//# sourceMappingURL=auth.guard.js.map
import { __awaiter } from "tslib";
import { Injectable } from '@angular/core';
import { defer, of, Subject } from 'rxjs';
import { first, map, mergeMap, shareReplay, tap } from 'rxjs/operators';
import { first, map, mergeMap, shareReplay, take, tap } from 'rxjs/operators';
import { AuthConfig } from './auth-config';

@@ -30,3 +30,8 @@ import { AuthEvent } from './auth-event';

*/
export const hasSomeAllowedRoles = (allowedRoles, actualRoles) => allowedRoles.length === 0 || allowedRoles.includes(anonymousRole) || allowedRoles.some(r => actualRoles.includes(r));
export const hasSomeAllowedRoles = (allowedRoles, actualRoles) => {
const allowedRoleNames = allowedRoles.flat(10);
return (allowedRoleNames.length === 0 ||
allowedRoleNames.includes(anonymousRole) ||
allowedRoleNames.some(r => actualRoles.includes(r)));
};
/**

@@ -50,3 +55,3 @@ * The main service for working with authenticated users

this.sessionEvents$ = this.sessionEvents.asObservable();
this.userLoaded$ = defer(() => this.httpGet('/.auth/me')).pipe(map(resp => resp.clientPrincipal), tap(user => {
this.currentUser$ = defer(() => this.httpGet('/.auth/me')).pipe(map(resp => resp.clientPrincipal), tap(user => {
if (user) {

@@ -56,4 +61,4 @@ this.publishAuthenticatedSuccessEvents(user);

}), shareReplay({ bufferSize: 1, refCount: false }));
this.isAuthenticated$ = this.userLoaded$.pipe(map(user => !!user), shareReplay({ bufferSize: 1, refCount: false }));
this.currentIdp$ = this.userLoaded$.pipe(map(user => user === null || user === void 0 ? void 0 : user.identityProvider));
this.isAuthenticated$ = this.currentUser$.pipe(map(user => !!user), shareReplay({ bufferSize: 1, refCount: false }));
this.currentIdp$ = this.currentUser$.pipe(map(user => user === null || user === void 0 ? void 0 : user.identityProvider));
}

@@ -72,3 +77,3 @@ /**

return __awaiter(this, void 0, void 0, function* () {
const user = yield this.userLoaded$.pipe(first()).toPromise();
const user = yield this.currentUser$.pipe(first()).toPromise();
if (user) {

@@ -82,7 +87,11 @@ return true;

/**
* Does the current user have one or more of the `allowedRoles` supplied
* Does the current user have one or more of the `allowedRoles` supplied.
*
* Note: because the observable returned completes, consumers do NOT have to unsubscribe from it
*
* @param allowedRoles The list of roles to check
* @return {Observable<boolean>} an observable that returns true/false and then completes
*/
hasSomeRoles$(allowedRoles) {
return this.userLoaded$.pipe(map(user => { var _a; return hasSomeAllowedRoles(allowedRoles, (_a = user === null || user === void 0 ? void 0 : user.userRoles) !== null && _a !== void 0 ? _a : noExplicitRoles); }));
return this.currentUser$.pipe(map(user => { var _a; return hasSomeAllowedRoles(allowedRoles, (_a = user === null || user === void 0 ? void 0 : user.userRoles) !== null && _a !== void 0 ? _a : noExplicitRoles); }), take(1));
}

@@ -117,3 +126,3 @@ /**

return __awaiter(this, void 0, void 0, function* () {
const user = yield this.userLoaded$.toPromise();
const user = yield this.currentUser$.toPromise();
if (!user) {

@@ -137,3 +146,3 @@ return false;

return __awaiter(this, void 0, void 0, function* () {
const user = yield this.userLoaded$.toPromise();
const user = yield this.currentUser$.toPromise();
if (!user) {

@@ -140,0 +149,0 @@ return false;

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { map, take } from 'rxjs/operators';
import { from, of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { AuthConfig } from './auth-config';

@@ -13,8 +14,13 @@ import { AuthService } from './auth.service';

*
* Implements `CanActivate` to verify that the current user is a member of one or more roles
* as defined in an `allowedRoles` field on `Route.data` for the route about to be navigated to
* Implements `CanLoad` for use with lazy loaded routes and `CanActivate` for regular routes.
*
* Will first trigger the sign in flow when the user is not already authenticated. Then verifies
* that the user is a member of one or more {@link AllowedRole}'s as defined in an `allowedRoles`
* field on `Route.data` for the route about to be navigated to.
*
* Where the user is deemed unauthorized the SPA will be routed to the client-side route configured
* using {@link AuthConfig.unauthorizedRoute}
*
* @see {AuthService.hasSomeRoles$}
*
* @example

@@ -24,8 +30,16 @@ * ```ts

* {
* path: 'admin-page',
* path: 'product-admin',
* data: {
* allowedRoles: 'admin' // or ['admin',]
* allowedRoles: 'admin' // other ex: ['admin', 'owner'] ['admin', ['product-reader', 'owner']]
* },
* canActivate: [SwaRoleGuard],
* component: AdminComponent
* },
* {
* path: 'user-admin',
* data: {
* allowedRoles: 'owner'
* },
* canLoad: [SwaRoleGuard],
* loadChildren: () => import('@christianacca/demo-app/user-admin').then(m => m.UserAdminModule)
* }

@@ -41,10 +55,41 @@ * ];

}
canActivate(route) {
const roles = route.data['allowedRoles'];
static getAllowedRoles(route) {
var _a;
const roles = (_a = route.data) === null || _a === void 0 ? void 0 : _a.allowedRoles;
if (!roles) {
return undefined;
}
return Array.isArray(roles) ? roles : [roles];
}
canActivate(route, state) {
return this.ensureHasRouteRoles(route, state.url);
}
canLoad(route) {
const navigation = this.router.getCurrentNavigation();
const targetUrl = !navigation ? '/' : navigation.extractedUrl.toString();
return this.ensureHasRouteRoles(route, targetUrl);
}
ensureHasRouteRoles(route, targetUrl) {
// Q: why are we calling `ensureLoggedIn` below?
// A: Angular will execute CanLoad guards BEFORE CanActivate guards
// Therefore this guard runs BEFORE the AuthGuard. As a consequence, this guard also
// needs to trigger the login flow.
const allowedRoles = SwaRoleGuard.getAllowedRoles(route);
if (!allowedRoles) {
return true;
}
const allowedRoles = Array.isArray(roles) ? roles : [roles];
return this.authService.hasSomeRoles$(allowedRoles).pipe(map(isAuthorized => isAuthorized || this.router.parseUrl(this.config.unauthorizedRoute)), take(1));
const isLoggedIn$ = from(this.authService.ensureLoggedIn(targetUrl));
return isLoggedIn$.pipe(switchMap(isLoggedIn => {
if (!isLoggedIn) {
// the user cancelled login prompt
return of(false);
}
return this.ensureHasSomeRoles(allowedRoles);
}));
}
ensureHasSomeRoles(allowedRoles) {
return this.authService
.hasSomeRoles$(allowedRoles)
.pipe(map(isAuthorized => isAuthorized || this.router.parseUrl(this.config.unauthorizedRoute)));
}
}

@@ -51,0 +96,0 @@ SwaRoleGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: SwaRoleGuard, deps: [{ token: i1.AuthService }, { token: i2.Router }, { token: i3.AuthConfig }], target: i0.ɵɵFactoryTarget.Injectable });

@@ -18,8 +18,8 @@ import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

* ```html
* <nav class="menu" *swaRoleCheck="let isAdmin of ['admin']; let maybeAdmin = isPlaceholder">
* <nav class="menu" *swaRoleCheck="let canAdmin of ['admin']; let maybeCanAdmin = isPlaceholder">
* <p class="menu-label">Menu</p>
* <ul class="menu-list">
* <a routerLink="/users" routerLinkActive="is-active">
* <progress *ngIf="maybeAdmin" class="progress is-primary is-medium" max="100">15%</progress>
* <span *ngIf="!maybeAdmin" [ngClass]="!isAdmin ? 'has-text-grey-lighter' : ''">Users</span>
* <progress *ngIf="maybeCanAdmin" class="progress is-primary is-medium" max="100">15%</progress>
* <span *ngIf="!maybeCanAdmin" [ngClass]="!canAdmin ? 'has-text-grey-lighter' : ''">Users</span>
* </a>

@@ -60,3 +60,3 @@ * </ul>

ngOnInit() {
const injectedRoles$ = this.authService.userLoaded$.pipe(map(user => user === null || user === void 0 ? void 0 : user.userRoles), takeUntil(this.userRolesFromTemplate));
const injectedRoles$ = this.authService.currentUser$.pipe(map(user => user === null || user === void 0 ? void 0 : user.userRoles), takeUntil(this.userRolesFromTemplate));
const userRoles$ = merge(this.userRolesFromTemplate, injectedRoles$).pipe(map(x => x !== null && x !== void 0 ? x : noExplicitRoles));

@@ -63,0 +63,0 @@ const permissionCheck$ = combineLatest([this.allowedRoles, userRoles$]).pipe(map(([allowedRoles, userRoles]) => hasSomeAllowedRoles(allowedRoles, userRoles)));

@@ -5,3 +5,3 @@ import { HttpErrorResponse, HTTP_INTERCEPTORS } from '@angular/common/http';

import { of, Subject, defer, Subscription, EMPTY, from, throwError, ReplaySubject, merge, combineLatest, BehaviorSubject } from 'rxjs';
import { map, tap, shareReplay, first, mergeMap, concatMap, catchError, takeUntil, take } from 'rxjs/operators';
import { map, tap, shareReplay, first, take, mergeMap, concatMap, catchError, takeUntil, switchMap } from 'rxjs/operators';
import { __awaiter } from 'tslib';

@@ -218,3 +218,8 @@ import * as i2 from '@angular/router';

*/
const hasSomeAllowedRoles = (allowedRoles, actualRoles) => allowedRoles.length === 0 || allowedRoles.includes(anonymousRole) || allowedRoles.some(r => actualRoles.includes(r));
const hasSomeAllowedRoles = (allowedRoles, actualRoles) => {
const allowedRoleNames = allowedRoles.flat(10);
return (allowedRoleNames.length === 0 ||
allowedRoleNames.includes(anonymousRole) ||
allowedRoleNames.some(r => actualRoles.includes(r)));
};
/**

@@ -238,3 +243,3 @@ * The main service for working with authenticated users

this.sessionEvents$ = this.sessionEvents.asObservable();
this.userLoaded$ = defer(() => this.httpGet('/.auth/me')).pipe(map(resp => resp.clientPrincipal), tap(user => {
this.currentUser$ = defer(() => this.httpGet('/.auth/me')).pipe(map(resp => resp.clientPrincipal), tap(user => {
if (user) {

@@ -244,4 +249,4 @@ this.publishAuthenticatedSuccessEvents(user);

}), shareReplay({ bufferSize: 1, refCount: false }));
this.isAuthenticated$ = this.userLoaded$.pipe(map(user => !!user), shareReplay({ bufferSize: 1, refCount: false }));
this.currentIdp$ = this.userLoaded$.pipe(map(user => user === null || user === void 0 ? void 0 : user.identityProvider));
this.isAuthenticated$ = this.currentUser$.pipe(map(user => !!user), shareReplay({ bufferSize: 1, refCount: false }));
this.currentIdp$ = this.currentUser$.pipe(map(user => user === null || user === void 0 ? void 0 : user.identityProvider));
}

@@ -260,3 +265,3 @@ /**

return __awaiter(this, void 0, void 0, function* () {
const user = yield this.userLoaded$.pipe(first()).toPromise();
const user = yield this.currentUser$.pipe(first()).toPromise();
if (user) {

@@ -270,7 +275,11 @@ return true;

/**
* Does the current user have one or more of the `allowedRoles` supplied
* Does the current user have one or more of the `allowedRoles` supplied.
*
* Note: because the observable returned completes, consumers do NOT have to unsubscribe from it
*
* @param allowedRoles The list of roles to check
* @return {Observable<boolean>} an observable that returns true/false and then completes
*/
hasSomeRoles$(allowedRoles) {
return this.userLoaded$.pipe(map(user => { var _a; return hasSomeAllowedRoles(allowedRoles, (_a = user === null || user === void 0 ? void 0 : user.userRoles) !== null && _a !== void 0 ? _a : noExplicitRoles$1); }));
return this.currentUser$.pipe(map(user => { var _a; return hasSomeAllowedRoles(allowedRoles, (_a = user === null || user === void 0 ? void 0 : user.userRoles) !== null && _a !== void 0 ? _a : noExplicitRoles$1); }), take(1));
}

@@ -305,3 +314,3 @@ /**

return __awaiter(this, void 0, void 0, function* () {
const user = yield this.userLoaded$.toPromise();
const user = yield this.currentUser$.toPromise();
if (!user) {

@@ -325,3 +334,3 @@ return false;

return __awaiter(this, void 0, void 0, function* () {
const user = yield this.userLoaded$.toPromise();
const user = yield this.currentUser$.toPromise();
if (!user) {

@@ -498,8 +507,8 @@ return false;

* ```html
* <nav class="menu" *swaRoleCheck="let isAdmin of ['admin']; let maybeAdmin = isPlaceholder">
* <nav class="menu" *swaRoleCheck="let canAdmin of ['admin']; let maybeCanAdmin = isPlaceholder">
* <p class="menu-label">Menu</p>
* <ul class="menu-list">
* <a routerLink="/users" routerLinkActive="is-active">
* <progress *ngIf="maybeAdmin" class="progress is-primary is-medium" max="100">15%</progress>
* <span *ngIf="!maybeAdmin" [ngClass]="!isAdmin ? 'has-text-grey-lighter' : ''">Users</span>
* <progress *ngIf="maybeCanAdmin" class="progress is-primary is-medium" max="100">15%</progress>
* <span *ngIf="!maybeCanAdmin" [ngClass]="!canAdmin ? 'has-text-grey-lighter' : ''">Users</span>
* </a>

@@ -540,3 +549,3 @@ * </ul>

ngOnInit() {
const injectedRoles$ = this.authService.userLoaded$.pipe(map(user => user === null || user === void 0 ? void 0 : user.userRoles), takeUntil(this.userRolesFromTemplate));
const injectedRoles$ = this.authService.currentUser$.pipe(map(user => user === null || user === void 0 ? void 0 : user.userRoles), takeUntil(this.userRolesFromTemplate));
const userRoles$ = merge(this.userRolesFromTemplate, injectedRoles$).pipe(map(x => x !== null && x !== void 0 ? x : noExplicitRoles));

@@ -616,10 +625,14 @@ const permissionCheck$ = combineLatest([this.allowedRoles, userRoles$]).pipe(map(([allowedRoles, userRoles]) => hasSomeAllowedRoles(allowedRoles, userRoles)));

*
* Implements `CanActivate` to ensure the user is authenticated before allowing the navigation to the route.
* Where the user is not yet authenticated, trigger the login flow.
* @see { AuthService.ensureLoggedIn}
* Implements `CanLoad` for use with lazy loaded routes and `CanActivate` for regular routes.
*
* @see { AuthService.ensureLoggedIn }
* @example
* ```ts
* export const routes: Routes = [
* { path: '', pathMatch: 'full', redirectTo: 'secure-page' },
* { path: 'secure-page', component: SecurePageComponent, canActivate: [AuthGuard] }
* { path: 'secure-page', component: SecurePageComponent, canActivate: [AuthGuard] },
* {
* path: 'product',
* canLoad: [AuthGuard],
* loadChildren: () => import('@christianacca/demo-app/product-admin').then(m => m.ProductAdminModule)
* },
* ];

@@ -629,4 +642,5 @@ * ```

class AuthGuard {
constructor(authService) {
constructor(authService, router) {
this.authService = authService;
this.router = router;
}

@@ -636,4 +650,9 @@ canActivate(_route, state) {

}
canLoad( /* route: Route, segments: UrlSegment[] */) {
const navigation = this.router.getCurrentNavigation();
const targetUrl = !navigation ? '/' : navigation.extractedUrl.toString();
return this.authService.ensureLoggedIn(targetUrl);
}
}
AuthGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AuthGuard, deps: [{ token: AuthService }], target: i0.ɵɵFactoryTarget.Injectable });
AuthGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AuthGuard, deps: [{ token: AuthService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
AuthGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AuthGuard, providedIn: 'root' });

@@ -645,3 +664,3 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: AuthGuard, decorators: [{

}]
}], ctorParameters: function () { return [{ type: AuthService }]; } });
}], ctorParameters: function () { return [{ type: AuthService }, { type: i2.Router }]; } });

@@ -651,8 +670,13 @@ /**

*
* Implements `CanActivate` to verify that the current user is a member of one or more roles
* as defined in an `allowedRoles` field on `Route.data` for the route about to be navigated to
* Implements `CanLoad` for use with lazy loaded routes and `CanActivate` for regular routes.
*
* Will first trigger the sign in flow when the user is not already authenticated. Then verifies
* that the user is a member of one or more {@link AllowedRole}'s as defined in an `allowedRoles`
* field on `Route.data` for the route about to be navigated to.
*
* Where the user is deemed unauthorized the SPA will be routed to the client-side route configured
* using {@link AuthConfig.unauthorizedRoute}
*
* @see {AuthService.hasSomeRoles$}
*
* @example

@@ -662,8 +686,16 @@ * ```ts

* {
* path: 'admin-page',
* path: 'product-admin',
* data: {
* allowedRoles: 'admin' // or ['admin',]
* allowedRoles: 'admin' // other ex: ['admin', 'owner'] ['admin', ['product-reader', 'owner']]
* },
* canActivate: [SwaRoleGuard],
* component: AdminComponent
* },
* {
* path: 'user-admin',
* data: {
* allowedRoles: 'owner'
* },
* canLoad: [SwaRoleGuard],
* loadChildren: () => import('@christianacca/demo-app/user-admin').then(m => m.UserAdminModule)
* }

@@ -679,10 +711,41 @@ * ];

}
canActivate(route) {
const roles = route.data['allowedRoles'];
static getAllowedRoles(route) {
var _a;
const roles = (_a = route.data) === null || _a === void 0 ? void 0 : _a.allowedRoles;
if (!roles) {
return undefined;
}
return Array.isArray(roles) ? roles : [roles];
}
canActivate(route, state) {
return this.ensureHasRouteRoles(route, state.url);
}
canLoad(route) {
const navigation = this.router.getCurrentNavigation();
const targetUrl = !navigation ? '/' : navigation.extractedUrl.toString();
return this.ensureHasRouteRoles(route, targetUrl);
}
ensureHasRouteRoles(route, targetUrl) {
// Q: why are we calling `ensureLoggedIn` below?
// A: Angular will execute CanLoad guards BEFORE CanActivate guards
// Therefore this guard runs BEFORE the AuthGuard. As a consequence, this guard also
// needs to trigger the login flow.
const allowedRoles = SwaRoleGuard.getAllowedRoles(route);
if (!allowedRoles) {
return true;
}
const allowedRoles = Array.isArray(roles) ? roles : [roles];
return this.authService.hasSomeRoles$(allowedRoles).pipe(map(isAuthorized => isAuthorized || this.router.parseUrl(this.config.unauthorizedRoute)), take(1));
const isLoggedIn$ = from(this.authService.ensureLoggedIn(targetUrl));
return isLoggedIn$.pipe(switchMap(isLoggedIn => {
if (!isLoggedIn) {
// the user cancelled login prompt
return of(false);
}
return this.ensureHasSomeRoles(allowedRoles);
}));
}
ensureHasSomeRoles(allowedRoles) {
return this.authService
.hasSomeRoles$(allowedRoles)
.pipe(map(isAuthorized => isAuthorized || this.router.parseUrl(this.config.unauthorizedRoute)));
}
}

@@ -689,0 +752,0 @@ SwaRoleGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.5", ngImport: i0, type: SwaRoleGuard, deps: [{ token: AuthService }, { token: i2.Router }, { token: AuthConfig }], target: i0.ɵɵFactoryTarget.Injectable });

@@ -1,3 +0,2 @@

import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';
import { ActivatedRouteSnapshot, CanActivate, CanLoad, Router, RouterStateSnapshot } from '@angular/router';
import { AuthService } from './auth.service';

@@ -8,19 +7,25 @@ import * as i0 from "@angular/core";

*
* Implements `CanActivate` to ensure the user is authenticated before allowing the navigation to the route.
* Where the user is not yet authenticated, trigger the login flow.
* @see { AuthService.ensureLoggedIn}
* Implements `CanLoad` for use with lazy loaded routes and `CanActivate` for regular routes.
*
* @see { AuthService.ensureLoggedIn }
* @example
* ```ts
* export const routes: Routes = [
* { path: '', pathMatch: 'full', redirectTo: 'secure-page' },
* { path: 'secure-page', component: SecurePageComponent, canActivate: [AuthGuard] }
* { path: 'secure-page', component: SecurePageComponent, canActivate: [AuthGuard] },
* {
* path: 'product',
* canLoad: [AuthGuard],
* loadChildren: () => import('@christianacca/demo-app/product-admin').then(m => m.ProductAdminModule)
* },
* ];
* ```
*/
export declare class AuthGuard implements CanActivate {
export declare class AuthGuard implements CanActivate, CanLoad {
private authService;
constructor(authService: AuthService);
canActivate(_route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree;
private router;
constructor(authService: AuthService, router: Router);
canActivate(_route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean>;
canLoad(): Promise<boolean>;
static ɵfac: i0.ɵɵFactoryDeclaration<AuthGuard, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<AuthGuard>;
}

@@ -8,2 +8,3 @@ import { Observable, Subject } from 'rxjs';

import * as i0 from "@angular/core";
export declare type AllowedRole = string | AllowedRole[];
/**

@@ -50,3 +51,3 @@ * Options that control the behaviour when purging user information

*/
export declare const hasSomeAllowedRoles: (allowedRoles: string[], actualRoles: string[]) => boolean;
export declare const hasSomeAllowedRoles: (allowedRoles: AllowedRole[], actualRoles: string[]) => boolean;
/**

@@ -60,2 +61,10 @@ * The main service for working with authenticated users

/**
* Return the current authenticated user or `null` when the user is not authenticated.
*
* The first subscriber will trigger a fetch from the built-in user api endpoint. Late subscribers will then receive
* the last value emitted.
*
*/
currentUser$: Observable<ClientPrincipal | null>;
/**
* The identity providers available to login with.

@@ -78,10 +87,2 @@ * Note: This is just a convenient alias of `AuthConfig.identityProviders`

sessionEvents$: Observable<AuthEvent>;
/**
* An event that will emit user details is fetched from the api. The value emitted will
* be undefined when the user is not authenticated
*
* Late subscribers will receive the last value emitted.
*
*/
userLoaded$: Observable<ClientPrincipal | null>;
private currentIdp$;

@@ -101,6 +102,10 @@ constructor(config: AuthConfig, storage: StorageService, idpSelectorService: IdentityProviderSelectorService);

/**
* Does the current user have one or more of the `allowedRoles` supplied
* Does the current user have one or more of the `allowedRoles` supplied.
*
* Note: because the observable returned completes, consumers do NOT have to unsubscribe from it
*
* @param allowedRoles The list of roles to check
* @return {Observable<boolean>} an observable that returns true/false and then completes
*/
hasSomeRoles$(allowedRoles: string[]): Observable<boolean>;
hasSomeRoles$(allowedRoles: AllowedRole[]): Observable<boolean>;
/**

@@ -107,0 +112,0 @@ * Trigger the login flow, redirecting the browser to the identity provider.

@@ -1,2 +0,2 @@

import { ActivatedRouteSnapshot, CanActivate, Router, UrlTree } from '@angular/router';
import { ActivatedRouteSnapshot, CanActivate, CanLoad, Route, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';

@@ -9,8 +9,13 @@ import { AuthConfig } from './auth-config';

*
* Implements `CanActivate` to verify that the current user is a member of one or more roles
* as defined in an `allowedRoles` field on `Route.data` for the route about to be navigated to
* Implements `CanLoad` for use with lazy loaded routes and `CanActivate` for regular routes.
*
* Will first trigger the sign in flow when the user is not already authenticated. Then verifies
* that the user is a member of one or more {@link AllowedRole}'s as defined in an `allowedRoles`
* field on `Route.data` for the route about to be navigated to.
*
* Where the user is deemed unauthorized the SPA will be routed to the client-side route configured
* using {@link AuthConfig.unauthorizedRoute}
*
* @see {AuthService.hasSomeRoles$}
*
* @example

@@ -20,8 +25,16 @@ * ```ts

* {
* path: 'admin-page',
* path: 'product-admin',
* data: {
* allowedRoles: 'admin' // or ['admin',]
* allowedRoles: 'admin' // other ex: ['admin', 'owner'] ['admin', ['product-reader', 'owner']]
* },
* canActivate: [SwaRoleGuard],
* component: AdminComponent
* },
* {
* path: 'user-admin',
* data: {
* allowedRoles: 'owner'
* },
* canLoad: [SwaRoleGuard],
* loadChildren: () => import('@christianacca/demo-app/user-admin').then(m => m.UserAdminModule)
* }

@@ -31,3 +44,3 @@ * ];

*/
export declare class SwaRoleGuard implements CanActivate {
export declare class SwaRoleGuard implements CanActivate, CanLoad {
private authService;

@@ -37,5 +50,9 @@ private router;

constructor(authService: AuthService, router: Router, config: AuthConfig);
canActivate(route: ActivatedRouteSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree;
private static getAllowedRoles;
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean | UrlTree>;
canLoad(route: Route): boolean | Observable<boolean | UrlTree>;
private ensureHasRouteRoles;
private ensureHasSomeRoles;
static ɵfac: i0.ɵɵFactoryDeclaration<SwaRoleGuard, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<SwaRoleGuard>;
}
import { OnDestroy, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';
import { AuthService } from './auth.service';
import { AllowedRole, AuthService } from './auth.service';
import * as i0 from "@angular/core";

@@ -11,8 +11,8 @@ /**

* ```html
* <nav class="menu" *swaRoleCheck="let isAdmin of ['admin']; let maybeAdmin = isPlaceholder">
* <nav class="menu" *swaRoleCheck="let canAdmin of ['admin']; let maybeCanAdmin = isPlaceholder">
* <p class="menu-label">Menu</p>
* <ul class="menu-list">
* <a routerLink="/users" routerLinkActive="is-active">
* <progress *ngIf="maybeAdmin" class="progress is-primary is-medium" max="100">15%</progress>
* <span *ngIf="!maybeAdmin" [ngClass]="!isAdmin ? 'has-text-grey-lighter' : ''">Users</span>
* <progress *ngIf="maybeCanAdmin" class="progress is-primary is-medium" max="100">15%</progress>
* <span *ngIf="!maybeCanAdmin" [ngClass]="!canAdmin ? 'has-text-grey-lighter' : ''">Users</span>
* </a>

@@ -27,3 +27,3 @@ * </ul>

private authService;
set swaRoleCheckOf(value: string[]);
set swaRoleCheckOf(value: AllowedRole[]);
set swaRoleCheckUserRoles(value: string[]);

@@ -30,0 +30,0 @@ private allowedRoles;

{
"name": "@christianacca/angular-swa-auth",
"description": "Programmatically work with Azure Static Web Apps authentication in an angular app",
"version": "1.1.2",
"version": "2.0.0-beta.1",
"keywords": [

@@ -6,0 +6,0 @@ "azure",

@@ -142,4 +142,29 @@ # @christianacca/angular-swa-auth

```
4. Optionally add `SwaRoleGuard` to your route(s)
```ts
import { AuthGuard } from '@christianacca/angular-swa-auth';
4. Optionally send authentication session events to your function app api
const routes: Route[] = [
{
path: 'product-admin',
data: {
allowedRoles: 'admin' // other ex: ['admin', 'owner'] ['admin', ['product-reader', 'owner']]
},
canActivate: [SwaRoleGuard],
component: AdminComponent
},
{
path: 'user-admin',
data: {
allowedRoles: 'owner'
},
canLoad: [SwaRoleGuard],
loadChildren: () => import('@christianacca/demo-app/user-admin').then(m => m.UserAdminModule)
}
];
```
5. Optionally send authentication session events to your function app api

@@ -146,0 +171,0 @@ ```ts

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc