diff --git a/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.scss b/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.scss
new file mode 100644
index 00000000..db459e7c
--- /dev/null
+++ b/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.scss
@@ -0,0 +1,8 @@
+.configurations {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ flex: 1 1 auto;
+}
diff --git a/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.ts b/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.ts
new file mode 100644
index 00000000..e641f945
--- /dev/null
+++ b/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.ts
@@ -0,0 +1,127 @@
+/*
+ Copyright NetFoundry Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+import {Component, OnInit} from '@angular/core';
+import {DataTableFilterService} from "../../features/data-table/data-table-filter.service";
+import {AuthPoliciesPageService} from "./auth-policies-page.service";
+import {TabNameService} from "../../services/tab-name.service";
+import {ListPageComponent} from "../../shared/list-page-component.class";
+import {ConsoleEventsService} from "../../services/console-events.service";
+import {MatDialog} from "@angular/material/dialog";
+import {ConfirmComponent} from "../../features/confirm/confirm.component";
+import {firstValueFrom} from "rxjs";
+
+
+@Component({
+ selector: 'lib-auth-policies',
+ templateUrl: './auth-policies-page.component.html',
+ styleUrls: ['./auth-policies-page.component.scss']
+})
+export class AuthPoliciesPageComponent extends ListPageComponent implements OnInit {
+ title = 'Auth Policies Management'
+ tabs: { url: string, label: string }[] ;
+ isLoading: boolean;
+ formDataChanged = false;
+
+ constructor(
+ override svc: AuthPoliciesPageService,
+ filterService: DataTableFilterService,
+ private tabNames: TabNameService,
+ consoleEvents: ConsoleEventsService,
+ dialogForm: MatDialog
+ ) {
+ super(filterService, svc, consoleEvents, dialogForm);
+ }
+
+ override ngOnInit() {
+ this.tabs = this.tabNames.getTabs('policies');
+ this.svc.refreshData = this.refreshData;
+ super.ngOnInit();
+ }
+
+ headerActionClicked(action: string) {
+ switch (action) {
+ case 'add':
+ this.svc.openEditForm();
+ break;
+ case 'edit':
+ this.svc.openEditForm();
+ break;
+ case 'delete':
+ let defaultPolicy;
+ const selectedItems = this.rowData.filter((row) => {
+ if (row.id === 'default') {
+ defaultPolicy = row;
+ }
+ return row.selected;
+ });
+ this.svc.checkDefaultAuthPolicy(defaultPolicy).then((result) => {
+ if (!result) {
+ return;
+ }
+ const label = selectedItems.length > 1 ? 'auth policies' : 'auth policy';
+ this.openBulkDelete(selectedItems, label);
+ });
+ break;
+ default:
+ }
+ }
+
+ tableAction(event: any) {
+ switch(event?.action) {
+ case 'toggleAll':
+ case 'toggleItem':
+ this.itemToggled(event.item)
+ break;
+ case 'update':
+ this.svc.checkDefaultAuthPolicy(event.item).then((result) => {
+ if (!result) {
+ return;
+ }
+ this.svc.openEditForm(event.item?.id);
+ });
+ break;
+ case 'create':
+ this.svc.openEditForm();
+ break;
+ case 'delete':
+ this.svc.checkDefaultAuthPolicy(event.item).then((result) => {
+ if (!result) {
+ return;
+ }
+ this.deleteItem(event.item)
+ });
+ break;
+ default:
+ break;
+ }
+ }
+
+ deleteItem(item: any) {
+ this.openBulkDelete([item], 'auth-policy');
+ }
+
+ closeModal(event: any) {
+ this.svc.sideModalOpen = false;
+ if(event?.refresh) {
+ this.refreshData();
+ }
+ }
+
+ dataChanged(event) {
+ this.formDataChanged = event;
+ }
+}
diff --git a/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.service.ts b/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.service.ts
new file mode 100644
index 00000000..106ca54d
--- /dev/null
+++ b/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.service.ts
@@ -0,0 +1,215 @@
+/*
+ Copyright NetFoundry Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+import {Inject, Injectable} from '@angular/core';
+import {DataTableFilterService, FilterObj} from "../../features/data-table/data-table-filter.service";
+import _, {isEmpty, unset} from "lodash";
+import moment from "moment";
+import {ListPageServiceClass} from "../../shared/list-page-service.class";
+import {
+ TableColumnDefaultComponent
+} from "../../features/data-table/column-headers/table-column-default/table-column-default.component";
+import {CallbackResults} from "../../features/list-page-features/list-page-form/list-page-form.component";
+import {SchemaService} from "../../services/schema.service";
+import {SETTINGS_SERVICE, SettingsService} from "../../services/settings.service";
+import {CsvDownloadService} from "../../services/csv-download.service";
+import {ExtensionService, SHAREDZ_EXTENSION} from "../../features/extendable/extensions-noop.service";
+import {Service} from "../../models/service";
+import {TableCellNameComponent} from "../../features/data-table/cells/table-cell-name/table-cell-name.component";
+import {Router} from "@angular/router";
+import {ConfirmComponent} from "../../features/confirm/confirm.component";
+import {firstValueFrom} from "rxjs";
+import {MatDialog} from "@angular/material/dialog";
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthPoliciesPageService extends ListPageServiceClass {
+
+ private paging = this.DEFAULT_PAGING;
+
+ resourceType = 'auth-policies';
+ selectedConfig: any = {};
+ modalType = '';
+
+ override menuItems = [
+ {name: 'Edit', action: 'update'},
+ {name: 'Delete', action: 'delete'},
+ ]
+
+ constructor(
+ private schemaSvc: SchemaService,
+ @Inject(SETTINGS_SERVICE) settings: SettingsService,
+ filterService: DataTableFilterService,
+ csvDownloadService: CsvDownloadService,
+ @Inject(SHAREDZ_EXTENSION) extService: ExtensionService,
+ protected override router: Router,
+ private dialogForm: MatDialog
+ ) {
+ super(settings, filterService, csvDownloadService, extService, router);
+ }
+
+ initTableColumns(): any {
+
+ const allowedHeaderComponentParams = {
+ filterType: 'SELECT',
+ enableSorting: true,
+ filterOptions: [
+ { label: 'All', value: '' },
+ { label: 'Allowed', value: true },
+ { label: 'Not Allowed', value: false },
+ ]
+ };
+ const createdAtHeaderComponentParams = {
+ filterType: 'DATETIME',
+ };
+ return [
+ {
+ colId: 'name',
+ field: 'name',
+ headerName: 'Name',
+ headerComponent: TableColumnDefaultComponent,
+ headerComponentParams: this.headerComponentParams,
+ cellRenderer: TableCellNameComponent,
+ cellRendererParams: { pathRoot: this.basePath, cellNamePreCheck: this.checkDefaultAuthPolicy.bind(this) },
+ onCellClicked: (data) => {
+ if (this.hasSelectedText()) {
+ return;
+ }
+ this.checkDefaultAuthPolicy(data?.data).then((result) => {
+ if (!result) {
+ return;
+ }
+ this.openEditForm(data?.data?.id);
+ });
+ },
+ resizable: true,
+ cellClass: 'nf-cell-vert-align tCol',
+ sortable: true,
+ filter: true,
+ sortColumn: this.sort.bind(this)
+ },
+ {
+ colId: 'primary.cert.allowed',
+ field: 'primary.cert.allowed',
+ headerName: 'Cert',
+ headerComponent: TableColumnDefaultComponent,
+ headerComponentParams: allowedHeaderComponentParams,
+ resizable: true,
+ cellClass: 'nf-cell-vert-align tCol',
+ sortable: true,
+ filter: true,
+ sortColumn: this.sort.bind(this),
+ },
+ {
+ colId: 'primary.extJwt.allowed',
+ field: 'primary.extJwt.allowed',
+ headerName: 'External JWT',
+ headerComponent: TableColumnDefaultComponent,
+ headerComponentParams: allowedHeaderComponentParams,
+ resizable: true,
+ cellClass: 'nf-cell-vert-align tCol',
+ sortable: true,
+ filter: true,
+ sortColumn: this.sort.bind(this),
+ },
+ {
+ colId: 'primary.updb.allowed',
+ field: 'primary.updb.allowed',
+ headerName: 'UPDB',
+ headerComponent: TableColumnDefaultComponent,
+ headerComponentParams: allowedHeaderComponentParams,
+ resizable: true,
+ cellClass: 'nf-cell-vert-align tCol',
+ sortable: true,
+ filter: true,
+ sortColumn: this.sort.bind(this),
+ },
+ {
+ colId: 'createdAt',
+ field: 'createdAt',
+ headerName: 'Created At',
+ headerComponent: TableColumnDefaultComponent,
+ headerComponentParams: createdAtHeaderComponentParams,
+ valueFormatter: this.createdAtFormatter,
+ resizable: true,
+ cellClass: 'nf-cell-vert-align tCol',
+ }
+ ];
+ }
+
+ checkDefaultAuthPolicy(authPolicy) {
+ if (authPolicy.id !== 'default') {
+ return Promise.resolve(true);
+ }
+ const confirmationMessage =
+ `
WARNING: Do not change the default policy unless you're sure you know what you are doing.
+
Before changing the default policy, it's recommended that you make another policy and apply that to other users first. Then make sure you can still authenticate.