Repository: kiali/kiali
Pull request #7568 (2024-07-29 15:28:04)

Add CSRF token to OSSMC non-GET request header
### Describe the change

The OpenShift console blocks any non-GET request that does not contain CSRF token in the request header. For this reason OSSMC has to add CSRF token in the non-GET request header to avoid a `403 Forbidden` response.

### Steps to test the PR

**Kiali**: This PR does not affect Kiali

**OSSMC**:
1. Execute `./hack/crc-openshift.sh start` to launch an OpenShift cluster
2. Install Istio via `./hack/istio/install-istio-via-istioctl.sh` and bookinfo demo `./hack/istio/install-bookinfo-demo.sh -tg -c oc`
3. cd to the kiali/kiali local repo and run this to prepare the image registry: `make cluster-status`
4. Look at the output of that make command to find the login command to the image registry and run that (it will be something like `podman login --tls-verify=false -u kubeadmin -p $(oc whoami -t) default-route-openshift-image-registry.apps-crc.testing`)
5. cd to OSSMC local repo (`main` branch), and execute `./hack/copy-frontend-src-to-ossmc.sh -pr 7568` to copy this PR into OSSMC code:
6. run `make cluster-push` to build and push the new plugin image to the cluster
7. cd back to kiali/kiali local repo and run this to install dev builds of everything (server, operator, and ossmc): `make build build-ui cluster-push operator-create kiali-create ossmconsole-create`
8. Go to the console via browser: `xdg-open https://console-openshift-console.apps-crc.testing/dashboards`
9. Go to the Service Mesh -> Overview page
10. Click on the options menu of any namespace and select `Enable injection` option, or perform any action that create/update any Istio object.
11. Verify that OSSMC is able to update the namespace/istio object.

### Automation testing

N/A

### Issue reference

Fixes https://github.com/kiali/openshift-servicemesh-plugin/issues/330



Patch:
diff --git a/config/config.go b/config/config.go
index 8d80c8046..002d89b55 100644
--- a/config/config.go
+++ b/config/config.go
@@ -968,6 +968,11 @@ func (conf *Config) GatewayLabel(labelConfig string) []string {
 	return []string{}
 }
 
+func (conf *Config) IsRBACDisabled() bool {
+	return conf.Auth.Strategy == AuthStrategyAnonymous ||
+		(conf.Auth.Strategy == AuthStrategyOpenId && conf.Auth.OpenId.DisableRBAC)
+}
+
 // Get the global Config
 func Get() (conf *Config) {
 	rwMutex.RLock()
diff --git a/frontend/package.json b/frontend/package.json
index 4563675bc..29411bebe 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -145,7 +145,7 @@
     "enzyme": "3.11.0",
     "enzyme-to-json": "3.4.4",
     "husky": "^8.0.3",
-    "i18next-parser": "^8.12.0",
+    "i18next-parser": "^9.0.1",
     "jest-canvas-mock": "2.2.0",
     "junit-report-merger": "^3.0.5",
     "mocha-junit-reporter": "^2.2.1",
@@ -164,6 +164,7 @@
     "@babel/plugin-transform-react-jsx": "^7.22.15",
     "async": "^3.2.2",
     "json-schema": "^0.4.0",
+    "micromatch": "^4.0.7",
     "minimist": "^1.2.6",
     "nth-check": "^2.0.1",
     "postcss": "^8.4.31",
diff --git a/frontend/public/locales/zh/translation.json b/frontend/public/locales/zh/translation.json
index 9ccc9ec8a..5f6d3904d 100644
--- a/frontend/public/locales/zh/translation.json
+++ b/frontend/public/locales/zh/translation.json
@@ -260,6 +260,7 @@
   "Virtual Service / Request Routing": "Virtual Service / Request Routing",
   "Visit the Mesh page": "Visit the Mesh page",
   "Warn": "Warn",
+  "Waypoint": "Waypoint",
   "Workload": "Workload",
   "Workload Entry": "Workload Entry",
   "Workloads": "工作负载",
diff --git a/frontend/src/assets/img/graph/node-badge-waypoint.svg b/frontend/src/assets/img/graph/node-badge-waypoint.svg
new file mode 100644
index 000000000..1cddf7044
--- /dev/null
+++ b/frontend/src/assets/img/graph/node-badge-waypoint.svg
@@ -0,0 +1,2 @@
+﻿<?xml version="1.0" standalone="no"?>
+<svg fill="#fff" height="27" width="27" viewBox="0 0 1424 1424" aria-hidden="true" role="img" style="vertical-align: -0.125em;margin: 4px" aria-describedby="pf-tooltip-2974" xmlns="http://www.w3.org/2000/svg"><path d="M592,64 C618.509668,64 640,85.490332 640,112 L640,112 L640,272 C640,272.7 639.9,273.5 639.9,274.3 L639.9,274.3 L749.6,384 L864,384 C881.673112,384 896,398.326888 896,416 L896,416 L896,544 C896,561.673112 881.673112,576 864,576 L864,576 L832,576 L832,639 L912,639 C938.509668,639 960,660.490332 960,687 L960,687 L960,768 L992,768 C1009.67311,768 1024,782.326888 1024,800 L1024,800 L1024,928 C1024,945.673112 1009.67311,960 992,960 L992,960 L864,960 C846.326888,960 832,945.673112 832,928 L832,928 L832,800 C832,782.326888 846.326888,768 864,768 L864,768 L896,768 L896,703 L704,703 L704,768 L736,768 C753.673112,768 768,782.326888 768,800 L768,800 L768,928 C768,945.673112 753.673112,960 736,960 L736,960 L608,960 C590.326888,960 576,945.673112 576,928 L576,928 L576,800 C576,782.326888 590.326888,768 608,768 L608,768 L640,768 L640,687 C640,660.490332 661.490332,639 688,639 L688,639 L768,639 L768,576 L736,576 C718.326888,576 704,561.673112 704,544 L704,544 L704,428.9 L595,319.9 C594,320 593,320 592,320 L592,320 L430.3,320 L320,430.3 L320,544 C320,561.673112 305.673112,576 288,576 L288,576 L256,576 L256,639 L336,639 C362.509668,639 384,660.490332 384,687 L384,687 L384,768 L416,768 C433.673112,768 448,782.326888 448,800 L448,800 L448,928 C448,945.673112 433.673112,960 416,960 L416,960 L288,960 C270.326888,960 256,945.673112 256,928 L256,928 L256,800 C256,782.326888 270.326888,768 288,768 L288,768 L320,768 L320,703 L128,703 L128,768 L160,768 C177.673112,768 192,782.326888 192,800 L192,800 L192,928 C192,945.673112 177.673112,960 160,960 L160,960 L32,960 C14.326888,960 0,945.673112 0,928 L0,928 L0,800 C0,782.326888 14.326888,768 32,768 L32,768 L64,768 L64,687 C64,660.490332 85.490332,639 112,639 L112,639 L192,639 L192,576 L160,576 C142.326888,576 128,561.673112 128,544 L128,544 L128,416 C128,398.326888 142.326888,384 160,384 L160,384 L275.7,384 L384.1,275.6 C384.1,274.4 384,273.2 384,272 L384,272 L384,112 C384,85.490332 405.490332,64 432,64 L432,64 Z M576,128 L448,128 L448,256 L576,256 L576,128 Z"></path></svg>
diff --git a/frontend/src/components/CytoscapeGraph/graphs/GraphStyles.ts b/frontend/src/components/CytoscapeGraph/graphs/GraphStyles.ts
index bf4a8de83..29cb30f53 100644
--- a/frontend/src/components/CytoscapeGraph/graphs/GraphStyles.ts
+++ b/frontend/src/components/CytoscapeGraph/graphs/GraphStyles.ts
@@ -70,6 +70,7 @@ const NodeIconRequestRouting = icons.istio.requestRouting.className; // code-bra
 const NodeIconRequestTimeout = icons.istio.requestTimeout.className; // clock
 const NodeIconTrafficShifting = icons.istio.trafficShifting.className; // share-alt
 const NodeIconWorkloadEntry = icons.istio.workloadEntry.className; // pf-icon-virtual-machine
+const NodeIconWaypoint = icons.istio.waypoint.className;
 const NodeTextColor = PFColors.Black1000;
 const NodeTextColorBox = PFColors.Black1000;
 const NodeTextBackgroundColor = PFColors.White;
@@ -240,6 +241,7 @@ export class GraphStyles {
     // const isClusterBoxed = box1Type === BoxByType.CLUSTER || box2Type === BoxByType.CLUSTER || box3Type === BoxByType.CLUSTER;
     const isMultiNamespace = cyGlobal.activeNamespaces.length > 1;
     const isOutside = node.isOutside;
+    const isWaypoint = node.isWaypoint || '';
 
     // Badges portion of label...
 
@@ -300,6 +302,9 @@ export class GraphStyles {
         if (node.isGateway?.egressInfo?.hostnames?.length !== undefined) {
           badges = `<span class="${NodeIconGateway} ${badgeMargin(badges)}"></span> ${badges}`;
         }
+        if (isWaypoint) {
+          badges = `<span class="${NodeIconWaypoint} ${badgeMargin(badges)}"></span> ${badges}`;
+        }
       }
     }
 
diff --git a/frontend/src/config/Icons.ts b/frontend/src/config/Icons.ts
index 77f32e4ea..5da869de0 100644
--- a/frontend/src/config/Icons.ts
+++ b/frontend/src/config/Icons.ts
@@ -8,6 +8,7 @@ import {
   ClockIcon,
   CodeBranchIcon,
   GlobeRouteIcon,
+  InfrastructureIcon,
   LockedIcon,
   MigrationIcon,
   SecurityIcon,
@@ -143,7 +144,15 @@ const mutIcons = {
       name: 'virtual-machine',
       text: 'Workload Entry',
       type: 'pf'
-    } as IconType
+    } as IconType,
+    waypoint: {
+      ascii: 'E93D ',
+      className: 'pf-v5-pficon pf-v5-pficon-infrastructure',
+      icon: InfrastructureIcon,
+      name: 'infrastructure',
+      text: 'Waypoint Proxy',
+      type: 'pf'
+    }
   }
 };
 
diff --git a/frontend/src/pages/Graph/GraphLegend.tsx b/frontend/src/pages/Graph/GraphLegend.tsx
index 8d62735b3..077153d41 100644
--- a/frontend/src/pages/Graph/GraphLegend.tsx
+++ b/frontend/src/pages/Graph/GraphLegend.tsx
@@ -100,7 +100,7 @@ export const GraphLegend: React.FC<GraphLegendProps> = (props: GraphLegendProps)
         </Tooltip>
       </div>
 
-      <div className={bodyStyle}>{renderGraphLegendList(legendData)}</div>
+      <div className={bodyStyle}>{renderGraphLegendList(legendData())}</div>
     </div>
   );
 };
diff --git a/frontend/src/pages/Graph/GraphLegendData.ts b/frontend/src/pages/Graph/GraphLegendData.ts
index 00856cbb5..55bb61b22 100644
--- a/frontend/src/pages/Graph/GraphLegendData.ts
+++ b/frontend/src/pages/Graph/GraphLegendData.ts
@@ -34,7 +34,9 @@ import badgeTrafficShiftingSourceImage from '../../assets/img/graph/node-badge-t
 import badgeTrafficSourceImage from '../../assets/img/graph/node-badge-traffic-source.svg';
 import badgeVirtualServicesImage from '../../assets/img/graph/node-badge-virtual-services.svg';
 import badgeWorkloadEntryImage from '../../assets/img/graph/node-badge-workload-entry.svg';
+import badgeWaypointImage from '../../assets/img/graph/node-badge-waypoint.svg';
 import { t } from 'utils/I18nUtils';
+import { serverConfig } from '../../config';
 
 export interface GraphLegendItem {
   data: GraphLegendItemRow[];
@@ -47,66 +49,74 @@ export interface GraphLegendItemRow {
   label: string;
 }
 
-export const legendData: GraphLegendItem[] = [
-  {
-    title: t('Node Shapes'),
-    data: [
-      { label: t('Workload'), icon: workloadImage },
-      { label: t('App'), icon: appImage },
-      { label: t('Operation'), icon: operationImage },
-      { label: t('Service'), icon: serviceImage },
-      { label: t('Service Entry'), icon: serviceEntryImage }
-    ]
-  },
-  {
-    title: t('Node Colors'),
-    data: [
-      { label: t('Normal'), icon: nodeColorNormalImage },
-      { label: t('Warn'), icon: nodeColorWarningImage },
-      { label: t('Unhealthy'), icon: nodeColorDangerImage },
-      { label: t('Idle'), icon: nodeColorIdleImage }
-    ]
-  },
-  {
-    title: t('Node Background'),
-    data: [
-      { label: t('Unselected Namespace'), icon: externalNamespaceImage },
-      { label: t('Restricted / External'), icon: restrictedNamespaceImage }
-    ]
-  },
-  {
-    title: t('Edges'),
-    data: [
-      { label: t('Failure'), icon: edgeDangerImage },
-      { label: t('Degraded'), icon: edgeWarnImage },
-      { label: t('Healthy'), icon: edgeSuccessImage },
-      { label: t('TCP Connection'), icon: edgeTcpImage },
-      { label: t('Idle'), icon: edgeIdlemage },
-      { label: t('mTLS (badge)'), icon: edgeMtlsImage }
-    ]
-  },
-  {
-    title: t('Traffic Animation'),
-    data: [
-      { label: t('Normal Request'), icon: trafficNormalImage },
-      { label: t('Failed Request'), icon: trafficFailedImage },
-      { label: t('TCP Traffic'), icon: trafficTcpImage }
-    ]
-  },
-  {
-    title: t('Node Badges'),
-    isBadge: true,
-    data: [
-      { label: t('Circuit Breaker'), icon: badgeCircuitBreakerImage },
-      { label: t('Fault Injection'), icon: badgeFaultInjectionImage },
-      { label: t('Gateway'), icon: badgeGatewaysImage },
-      { label: t('Mirroring'), icon: badgeMirroringImage },
-      { label: t('Missing Sidecar'), icon: badgeMissingSidecarImage },
-      { label: t('Request Timeout'), icon: badgeRequestTimeoutImage },
-      { label: t('Traffic Shifting / TCP Traffic Shifting'), icon: badgeTrafficShiftingSourceImage },
-      { label: t('Traffic Source'), icon: badgeTrafficSourceImage },
-      { label: t('Virtual Service / Request Routing'), icon: badgeVirtualServicesImage },
-      { label: t('Workload Entry'), icon: badgeWorkloadEntryImage }
-    ]
+export const legendData = (): GraphLegendItem[] => {
+  const nodesBadges = [
+    { label: t('Circuit Breaker'), icon: badgeCircuitBreakerImage },
+    { label: t('Fault Injection'), icon: badgeFaultInjectionImage },
+    { label: t('Gateway'), icon: badgeGatewaysImage },
+    { label: t('Mirroring'), icon: badgeMirroringImage },
+    { label: t('Missing Sidecar'), icon: badgeMissingSidecarImage },
+    { label: t('Request Timeout'), icon: badgeRequestTimeoutImage },
+    { label: t('Traffic Shifting / TCP Traffic Shifting'), icon: badgeTrafficShiftingSourceImage },
+    { label: t('Traffic Source'), icon: badgeTrafficSourceImage },
+    { label: t('Virtual Service / Request Routing'), icon: badgeVirtualServicesImage },
+    { label: t('Workload Entry'), icon: badgeWorkloadEntryImage }
+  ];
+
+  if (serverConfig.ambientEnabled) {
+    nodesBadges.push({ label: t('Waypoint'), icon: badgeWaypointImage });
   }
-];
+
+  return [
+    {
+      title: t('Node Shapes'),
+      data: [
+        { label: t('Workload'), icon: workloadImage },
+        { label: t('App'), icon: appImage },
+        { label: t('Operation'), icon: operationImage },
+        { label: t('Service'), icon: serviceImage },
+        { label: t('Service Entry'), icon: serviceEntryImage }
+      ]
+    },
+    {
+      title: t('Node Colors'),
+      data: [
+        { label: t('Normal'), icon: nodeColorNormalImage },
+        { label: t('Warn'), icon: nodeColorWarningImage },
+        { label: t('Unhealthy'), icon: nodeColorDangerImage },
+        { label: t('Idle'), icon: nodeColorIdleImage }
+      ]
+    },
+    {
+      title: t('Node Background'),
+      data: [
+        { label: t('Unselected Namespace'), icon: externalNamespaceImage },
+        { label: t('Restricted / External'), icon: restrictedNamespaceImage }
+      ]
+    },
+    {
+      title: t('Edges'),
+      data: [
+        { label: t('Failure'), icon: edgeDangerImage },
+        { label: t('Degraded'), icon: edgeWarnImage },
+        { label: t('Healthy'), icon: edgeSuccessImage },
+        { label: t('TCP Connection'), icon: edgeTcpImage },
+        { label: t('Idle'), icon: edgeIdlemage },
+        { label: t('mTLS (badge)'), icon: edgeMtlsImage }
+      ]
+    },
+    {
+      title: t('Traffic Animation'),
+      data: [
+        { label: t('Normal Request'), icon: trafficNormalImage },
+        { label: t('Failed Request'), icon: trafficFailedImage },
+        { label: t('TCP Traffic'), icon: trafficTcpImage }
+      ]
+    },
+    {
+      title: t('Node Badges'),
+      isBadge: true,
+      data: nodesBadges
+    }
+  ];
+};
diff --git a/frontend/src/pages/GraphPF/GraphLegendDataPF.ts b/frontend/src/pages/GraphPF/GraphLegendDataPF.ts
index 973819ee5..5d93c8a2f 100644
--- a/frontend/src/pages/GraphPF/GraphLegendDataPF.ts
+++ b/frontend/src/pages/GraphPF/GraphLegendDataPF.ts
@@ -34,7 +34,9 @@ import badgeTrafficShiftingSourceImage from '../../assets/img/graph/node-badge-t
 import badgeTrafficSourceImage from '../../assets/img/graph/node-badge-traffic-source.svg';
 import badgeVirtualServicesImage from '../../assets/img/graph/node-badge-virtual-services.svg';
 import badgeWorkloadEntryImage from '../../assets/img/graph/node-badge-workload-entry.svg';
+import badgeWaypointImage from '../../assets/img/graph/node-badge-waypoint.svg';
 import { t } from 'utils/I18nUtils';
+import { serverConfig } from '../../config';
 
 export interface GraphLegendItem {
   data: GraphLegendItemRow[];
@@ -47,66 +49,74 @@ export interface GraphLegendItemRow {
   label: string;
 }
 
-export const legendData: GraphLegendItem[] = [
-  {
-    title: t('Node Shapes'),
-    data: [
-      { label: t('Workload'), icon: workloadImage },
-      { label: t('App'), icon: appImage },
-      { label: t('Operation'), icon: operationImage },
-      { label: t('Service'), icon: serviceImage },
-      { label: t('Service Entry'), icon: serviceEntryImage }
-    ]
-  },
-  {
-    title: t('Node Colors'),
-    data: [
-      { label: t('Healthy'), icon: nodeColorHealthyImage },
-      { label: t('Warn'), icon: nodeColorWarningImage },
-      { label: t('Unhealthy'), icon: nodeColorDangerImage },
-      { label: t('Idle'), icon: nodeColorIdleImage }
-    ]
-  },
-  {
-    title: t('Node Background'),
-    data: [
-      { label: t('Unselected Namespace'), icon: externalNamespaceImage },
-      { label: t('Restricted / External'), icon: restrictedNamespaceImage }
-    ]
-  },
-  {
-    title: t('Edges'),
-    data: [
-      { label: t('Failure'), icon: edgeDangerImage },
-      { label: t('Degraded'), icon: edgeWarnImage },
-      { label: t('Healthy'), icon: edgeSuccessImage },
-      { label: t('TCP Connection'), icon: edgeTcpImage },
-      { label: t('Idle'), icon: edgeIdlemage },
-      { label: t('mTLS (badge)'), icon: edgeMtlsImage }
-    ]
-  },
-  {
-    title: t('Traffic Animation'),
-    data: [
-      { label: t('Healthy Request'), icon: trafficHealthyImage },
-      { label: t('Failed Request'), icon: trafficFailedImage },
-      { label: t('TCP Traffic'), icon: trafficTcpImage }
-    ]
-  },
-  {
-    title: t('Node Badges'),
-    isBadge: true,
-    data: [
-      { label: t('Circuit Breaker'), icon: badgeCircuitBreakerImage },
-      { label: t('Fault Injection'), icon: badgeFaultInjectionImage },
-      { label: t('Gateway'), icon: badgeGatewaysImage },
-      { label: t('Mirroring'), icon: badgeMirroringImage },
-      { label: t('Missing Sidecar'), icon: badgeMissingSidecarImage },
-      { label: t('Request Timeout'), icon: badgeRequestTimeoutImage },
-      { label: t('Traffic Shifting / TCP Traffic Shifting'), icon: badgeTrafficShiftingSourceImage },
-      { label: t('Traffic Source'), icon: badgeTrafficSourceImage },
-      { label: t('Virtual Service / Request Routing'), icon: badgeVirtualServicesImage },
-      { label: t('Workload Entry'), icon: badgeWorkloadEntryImage }
-    ]
+export const legendData = (): GraphLegendItem[] => {
+  const nodeBadges = [
+    { label: t('Circuit Breaker'), icon: badgeCircuitBreakerImage },
+    { label: t('Fault Injection'), icon: badgeFaultInjectionImage },
+    { label: t('Gateway'), icon: badgeGatewaysImage },
+    { label: t('Mirroring'), icon: badgeMirroringImage },
+    { label: t('Missing Sidecar'), icon: badgeMissingSidecarImage },
+    { label: t('Request Timeout'), icon: badgeRequestTimeoutImage },
+    { label: t('Traffic Shifting / TCP Traffic Shifting'), icon: badgeTrafficShiftingSourceImage },
+    { label: t('Traffic Source'), icon: badgeTrafficSourceImage },
+    { label: t('Virtual Service / Request Routing'), icon: badgeVirtualServicesImage },
+    { label: t('Workload Entry'), icon: badgeWorkloadEntryImage }
+  ];
+
+  if (serverConfig.ambientEnabled) {
+    nodeBadges.push({ label: t('Waypoint'), icon: badgeWaypointImage });
   }
-];
+
+  return [
+    {
+      title: t('Node Shapes'),
+      data: [
+        { label: t('Workload'), icon: workloadImage },
+        { label: t('App'), icon: appImage },
+        { label: t('Operation'), icon: operationImage },
+        { label: t('Service'), icon: serviceImage },
+        { label: t('Service Entry'), icon: serviceEntryImage }
+      ]
+    },
+    {
+      title: t('Node Colors'),
+      data: [
+        { label: t('Healthy'), icon: nodeColorHealthyImage },
+        { label: t('Warn'), icon: nodeColorWarningImage },
+        { label: t('Unhealthy'), icon: nodeColorDangerImage },
+        { label: t('Idle'), icon: nodeColorIdleImage }
+      ]
+    },
+    {
+      title: t('Node Background'),
+      data: [
+        { label: t('Unselected Namespace'), icon: externalNamespaceImage },
+        { label: t('Restricted / External'), icon: restrictedNamespaceImage }
+      ]
+    },
+    {
+      title: t('Edges'),
+      data: [
+        { label: t('Failure'), icon: edgeDangerImage },
+        { label: t('Degraded'), icon: edgeWarnImage },
+        { label: t('Healthy'), icon: edgeSuccessImage },
+        { label: t('TCP Connection'), icon: edgeTcpImage },
+        { label: t('Idle'), icon: edgeIdlemage },
+        { label: t('mTLS (badge)'), icon: edgeMtlsImage }
+      ]
+    },
+    {
+      title: t('Traffic Animation'),
+      data: [
+        { label: t('Healthy Request'), icon: trafficHealthyImage },
+        { label: t('Failed Request'), icon: trafficFailedImage },
+        { label: t('TCP Traffic'), icon: trafficTcpImage }
+      ]
+    },
+    {
+      title: t('Node Badges'),
+      isBadge: true,
+      data: nodeBadges
+    }
+  ];
+};
diff --git a/frontend/src/pages/GraphPF/GraphLegendPF.tsx b/frontend/src/pages/GraphPF/GraphLegendPF.tsx
index 7dded2123..fb2fe9552 100644
--- a/frontend/src/pages/GraphPF/GraphLegendPF.tsx
+++ b/frontend/src/pages/GraphPF/GraphLegendPF.tsx
@@ -99,7 +99,7 @@ export const GraphLegendPF: React.FC<GraphLegendPFProps> = (props: GraphLegendPF
         </Tooltip>
       </div>
 
-      <div className={bodyStyle}>{renderGraphLegendList(legendData)}</div>
+      <div className={bodyStyle}>{renderGraphLegendList(legendData())}</div>
     </div>
   );
 };
diff --git a/frontend/src/pages/GraphPF/GraphPFElems.tsx b/frontend/src/pages/GraphPF/GraphPFElems.tsx
index 70111628f..dd8f39333 100644
--- a/frontend/src/pages/GraphPF/GraphPFElems.tsx
+++ b/frontend/src/pages/GraphPF/GraphPFElems.tsx
@@ -115,7 +115,8 @@ const badgeMap = new Map<string, IconType>()
   .set('RT', icons.istio.requestTimeout) // clock
   .set('TS', icons.istio.trafficShifting) // share-alt
   .set('VS', icons.istio.virtualService) // code-branch
-  .set('WE', icons.istio.workloadEntry); // pf-icon-virtual-machine
+  .set('WE', icons.istio.workloadEntry) // pf-icon-virtual-machine
+  .set('WA', icons.istio.waypoint); // pf icon for infrastructure
 
 const EdgeColor = PFColors.Success;
 const EdgeColorDead = PFColors.Black500;
@@ -254,6 +255,11 @@ export const setNodeLabel = (node: NodeModel, nodeMap: NodeMap, settings: GraphP
     if (data.isGateway?.egressInfo?.hostnames?.length !== undefined) {
       data.labelIcon = <span className={`${badgeMap.get('GW')?.className}`}></span>;
     }
+    if (data.isWaypoint) {
+      data.labelIcon = (
+        <span className={`${badgeMap.get('WA')?.className}`} style={{ marginBottom: '1px', marginLeft: '2px' }}></span>
+      );
+    }
   }
 
   // Content portion of label (i.e. the text)...
diff --git a/frontend/src/services/Api.ts b/frontend/src/services/Api.ts
index 06d7b5811..0f963fd03 100644
--- a/frontend/src/services/Api.ts
+++ b/frontend/src/services/Api.ts
@@ -3,7 +3,7 @@ import { config } from '../config';
 import { LoginSession } from '../store/Store';
 import { App, AppQuery } from '../types/App';
 import { AppList, AppListQuery } from '../types/AppList';
-import { AuthInfo } from '../types/Auth';
+import { AuthInfo, getCSRFToken } from '../types/Auth';
 import { DurationInSeconds, HTTP_VERBS, Password, TimeInSeconds, UserName } from '../types/Common';
 import { DashboardModel } from 'types/Dashboards';
 import { GrafanaInfo } from '../types/GrafanaInfo';
@@ -65,6 +65,7 @@ import {
 } from '../types/Workload';
 import { CertsInfo } from 'types/CertsInfo';
 import { ApiError, ApiResponse } from 'types/Api';
+
 export const ANONYMOUS_USER = 'anonymous';
 
 interface ClusterParam {
@@ -104,10 +105,17 @@ const loginHeaders = config.login.headers;
 
 /**  Helpers to Requests */
 
-const getHeaders = (urlEncoded?: boolean): Partial<AxiosHeaders> => {
+const getHeaders = (method: HTTP_VERBS, urlEncoded: boolean): Partial<AxiosHeaders> => {
   if (apiProxy) {
     // apiProxy is used by OSSMC, which doesn't need Kiali login headers (and can cause CORS issues)
-    return { 'Content-Type': 'application/x-www-form-urlencoded' };
+    const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
+
+    // X-CSRFToken is used only for non-GET requests
+    if (method !== HTTP_VERBS.GET) {
+      headers['X-CSRFToken'] = getCSRFToken();
+    }
+
+    return headers;
   } else if (urlEncoded) {
     return { 'Content-Type': 'application/x-www-form-urlencoded', ...loginHeaders };
   } else {
@@ -132,7 +140,7 @@ const newRequest = <P>(
     method: method,
     url: apiProxy ? `${apiProxy}/${url}` : url,
     data: requestData,
-    headers: getHeaders() as AxiosHeaders,
+    headers: getHeaders(method, false) as AxiosHeaders,
     params: queryParams
   });
 };
@@ -148,10 +156,12 @@ export const login = async (
   const params = new URLSearchParams();
   params.append('token', request.token);
 
+  const method = HTTP_VERBS.POST;
+
   const axiosRequest = {
-    method: HTTP_VERBS.POST,
+    method: method,
     url: apiProxy ? `${apiProxy}/${urls.authenticate}` : urls.authenticate,
-    headers: getHeaders(true) as AxiosHeaders,
+    headers: getHeaders(method, true) as AxiosHeaders,
     data: params
   };
 
diff --git a/frontend/src/types/Auth.ts b/frontend/src/types/Auth.ts
index 5d8f6681c..28899f013 100644
--- a/frontend/src/types/Auth.ts
+++ b/frontend/src/types/Auth.ts
@@ -39,3 +39,18 @@ export interface SessionInfo {
   expiresOn?: string;
   username?: string;
 }
+
+export const getCSRFToken = (): string | undefined => {
+  const cookiePrefix = 'csrf-token=';
+
+  return (
+    document &&
+    document.cookie &&
+    document.cookie
+      .split(';')
+      .map(c => c.trim())
+      .filter(c => c.startsWith(cookiePrefix))
+      .map(c => c.slice(cookiePrefix.length))
+      .pop()
+  );
+};
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 7eeac2b9d..6598d5150 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -1517,56 +1517,111 @@
   resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f"
   integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==
 
+"@esbuild/aix-ppc64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537"
+  integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==
+
 "@esbuild/android-arm64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4"
   integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==
 
+"@esbuild/android-arm64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9"
+  integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==
+
 "@esbuild/android-arm@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824"
   integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==
 
+"@esbuild/android-arm@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995"
+  integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==
+
 "@esbuild/android-x64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d"
   integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==
 
+"@esbuild/android-x64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98"
+  integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==
+
 "@esbuild/darwin-arm64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e"
   integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==
 
+"@esbuild/darwin-arm64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb"
+  integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==
+
 "@esbuild/darwin-x64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd"
   integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==
 
+"@esbuild/darwin-x64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0"
+  integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==
+
 "@esbuild/freebsd-arm64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487"
   integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==
 
+"@esbuild/freebsd-arm64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911"
+  integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==
+
 "@esbuild/freebsd-x64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c"
   integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==
 
+"@esbuild/freebsd-x64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c"
+  integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==
+
 "@esbuild/linux-arm64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b"
   integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==
 
+"@esbuild/linux-arm64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5"
+  integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==
+
 "@esbuild/linux-arm@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef"
   integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==
 
+"@esbuild/linux-arm@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c"
+  integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==
+
 "@esbuild/linux-ia32@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601"
   integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==
 
+"@esbuild/linux-ia32@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa"
+  integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==
+
 "@esbuild/linux-loong64@0.14.54":
   version "0.14.54"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
@@ -1577,61 +1632,121 @@
   resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299"
   integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==
 
+"@esbuild/linux-loong64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5"
+  integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==
+
 "@esbuild/linux-mips64el@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec"
   integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==
 
+"@esbuild/linux-mips64el@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa"
+  integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==
+
 "@esbuild/linux-ppc64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8"
   integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==
 
+"@esbuild/linux-ppc64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20"
+  integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==
+
 "@esbuild/linux-riscv64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf"
   integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==
 
+"@esbuild/linux-riscv64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300"
+  integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==
+
 "@esbuild/linux-s390x@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8"
   integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==
 
+"@esbuild/linux-s390x@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685"
+  integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==
+
 "@esbuild/linux-x64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78"
   integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==
 
+"@esbuild/linux-x64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff"
+  integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==
+
 "@esbuild/netbsd-x64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b"
   integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==
 
+"@esbuild/netbsd-x64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6"
+  integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==
+
 "@esbuild/openbsd-x64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0"
   integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==
 
+"@esbuild/openbsd-x64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf"
+  integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==
+
 "@esbuild/sunos-x64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30"
   integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==
 
+"@esbuild/sunos-x64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f"
+  integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==
+
 "@esbuild/win32-arm64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae"
   integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==
 
+"@esbuild/win32-arm64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90"
+  integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==
+
 "@esbuild/win32-ia32@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67"
   integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==
 
+"@esbuild/win32-ia32@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23"
+  integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==
+
 "@esbuild/win32-x64@0.19.12":
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae"
   integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==
 
+"@esbuild/win32-x64@0.20.2":
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc"
+  integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==
+
 "@eslint-community/eslint-utils@^4.2.0":
   version "4.4.0"
   resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
@@ -3997,13 +4112,13 @@ bluebird@^3.5.5, bluebird@^3.7.2:
   resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
   integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
 
-body-parser@1.20.1:
-  version "1.20.1"
-  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
-  integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
+body-parser@1.20.2:
+  version "1.20.2"
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
+  integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
   dependencies:
     bytes "3.1.2"
-    content-type "~1.0.4"
+    content-type "~1.0.5"
     debug "2.6.9"
     depd "2.0.0"
     destroy "1.2.0"
@@ -4011,7 +4126,7 @@ body-parser@1.20.1:
     iconv-lite "0.4.24"
     on-finished "2.4.1"
     qs "6.11.0"
-    raw-body "2.5.1"
+    raw-body "2.5.2"
     type-is "~1.6.18"
     unpipe "1.0.0"
 
@@ -4050,12 +4165,12 @@ brace-expansion@^2.0.1:
   dependencies:
     balanced-match "^1.0.0"
 
-braces@^3.0.2, braces@~3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
-  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+braces@^3.0.3, braces@~3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+  integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
   dependencies:
-    fill-range "^7.0.1"
+    fill-range "^7.1.1"
 
 broccoli-node-api@^1.7.0:
   version "1.7.0"
@@ -4521,10 +4636,10 @@ commander@^8.3.0:
   resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
   integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
 
-commander@~11.1.0:
-  version "11.1.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906"
-  integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==
+commander@~12.1.0:
+  version "12.1.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3"
+  integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==
 
 common-ancestor-path@^1.0.1:
   version "1.0.1"
@@ -4588,7 +4703,7 @@ content-disposition@0.5.4:
   dependencies:
     safe-buffer "5.2.1"
 
-content-type@~1.0.4:
+content-type@~1.0.4, content-type@~1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
   integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
@@ -4608,10 +4723,10 @@ cookie-signature@1.0.6:
   resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
   integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
 
-cookie@0.5.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
-  integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
+cookie@0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
+  integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
 
 copy-to-clipboard@^3:
   version "3.3.1"
@@ -5326,11 +5441,6 @@ dayjs@^1.10.4:
   resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.9.tgz#9ca491933fadd0a60a2c19f6c237c03517d71d1a"
   integrity sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==
 
-de-indent@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
-  integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==
-
 debug@2.6.9, debug@^2.2.0, debug@^2.6.0:
   version "2.6.9"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -5689,9 +5799,9 @@ ee-first@1.1.1:
   integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
 
 ejs@^3.1.6:
-  version "3.1.9"
-  resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361"
-  integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==
+  version "3.1.10"
+  resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b"
+  integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==
   dependencies:
     jake "^10.8.5"
 
@@ -6038,7 +6148,7 @@ esbuild@^0.14.23:
     esbuild-windows-64 "0.14.54"
     esbuild-windows-arm64 "0.14.54"
 
-esbuild@^0.19.0, esbuild@^0.19.4:
+esbuild@^0.19.4:
   version "0.19.12"
   resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04"
   integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==
@@ -6067,6 +6177,35 @@ esbuild@^0.19.0, esbuild@^0.19.4:
     "@esbuild/win32-ia32" "0.19.12"
     "@esbuild/win32-x64" "0.19.12"
 
+esbuild@^0.20.1:
+  version "0.20.2"
+  resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.20.2.tgz#9d6b2386561766ee6b5a55196c6d766d28c87ea1"
+  integrity sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==
+  optionalDependencies:
+    "@esbuild/aix-ppc64" "0.20.2"
+    "@esbuild/android-arm" "0.20.2"
+    "@esbuild/android-arm64" "0.20.2"
+    "@esbuild/android-x64" "0.20.2"
+    "@esbuild/darwin-arm64" "0.20.2"
+    "@esbuild/darwin-x64" "0.20.2"
+    "@esbuild/freebsd-arm64" "0.20.2"
+    "@esbuild/freebsd-x64" "0.20.2"
+    "@esbuild/linux-arm" "0.20.2"
+    "@esbuild/linux-arm64" "0.20.2"
+    "@esbuild/linux-ia32" "0.20.2"
+    "@esbuild/linux-loong64" "0.20.2"
+    "@esbuild/linux-mips64el" "0.20.2"
+    "@esbuild/linux-ppc64" "0.20.2"
+    "@esbuild/linux-riscv64" "0.20.2"
+    "@esbuild/linux-s390x" "0.20.2"
+    "@esbuild/linux-x64" "0.20.2"
+    "@esbuild/netbsd-x64" "0.20.2"
+    "@esbuild/openbsd-x64" "0.20.2"
+    "@esbuild/sunos-x64" "0.20.2"
+    "@esbuild/win32-arm64" "0.20.2"
+    "@esbuild/win32-ia32" "0.20.2"
+    "@esbuild/win32-x64" "0.20.2"
+
 escalade@^3.1.1:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@@ -6448,16 +6587,16 @@ expect@^27.5.1:
     jest-message-util "^27.5.1"
 
 express@^4.17.3:
-  version "4.18.2"
-  resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
-  integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
+  version "4.19.2"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465"
+  integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==
   dependencies:
     accepts "~1.3.8"
     array-flatten "1.1.1"
-    body-parser "1.20.1"
+    body-parser "1.20.2"
     content-disposition "0.5.4"
     content-type "~1.0.4"
-    cookie "0.5.0"
+    cookie "0.6.0"
     cookie-signature "1.0.6"
     debug "2.6.9"
     depd "2.0.0"
@@ -6621,10 +6760,10 @@ filesize@^8.0.6:
   resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8"
   integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==
 
-fill-range@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
-  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
+fill-range@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+  integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
   dependencies:
     to-regex-range "^5.0.1"
 
@@ -7447,17 +7586,18 @@ i18next-http-backend@^2.5.0:
   dependencies:
     cross-fetch "4.0.0"
 
-i18next-parser@^8.12.0:
-  version "8.12.0"
-  resolved "https://registry.yarnpkg.com/i18next-parser/-/i18next-parser-8.12.0.tgz#1ed3c9acff82c17619ab6d5f232f8dc7f3fb572f"
-  integrity sha512-DUDFX3/nkECyd/zCqZoudTEtokMhOVX+zN8X8JasvYd/Lc/PsMcYuO2n0R7yzLiohXLj/7Hp20x0vAbuY8wo0Q==
+i18next-parser@^9.0.1:
+  version "9.0.1"
+  resolved "https://registry.yarnpkg.com/i18next-parser/-/i18next-parser-9.0.1.tgz#208917d1e6b524dcee81aaa6b71ef7572cbc1832"
+  integrity sha512-/Pr93/yEBdwsMKRsk4Zn63K368ALhzh8BRVrM6JNGOHy86ZKpiNJI6m8l1S/4T4Ofy1J4dlwkD7N98M70GP4aA==
   dependencies:
+    "@babel/runtime" "^7.23.2"
     broccoli-plugin "^4.0.7"
     cheerio "^1.0.0-rc.2"
     colors "1.4.0"
-    commander "~11.1.0"
+    commander "~12.1.0"
     eol "^0.9.1"
-    esbuild "^0.19.0"
+    esbuild "^0.20.1"
     fs-extra "^11.1.0"
     gulp-sort "^2.0.0"
     i18next "^23.5.1"
@@ -7468,7 +7608,6 @@ i18next-parser@^8.12.0:
     typescript "^5.0.4"
     vinyl "~3.0.0"
     vinyl-fs "^4.0.0"
-    vue-template-compiler "^2.6.11"
 
 i18next@^23.10.1:
   version "23.10.1"
@@ -8967,12 +9106,12 @@ micro-memoize@4.0.9:
   resolved "https://registry.yarnpkg.com/micro-memoize/-/micro-memoize-4.0.9.tgz#b44a38c9dffbee1cefc2fd139bc8947952268b62"
   integrity sha512-Z2uZi/IUMGQDCXASdujXRqrXXEwSY0XffUrAOllhqzQI3wpUyZbiZTiE2JuYC0HSG2G7DbCS5jZmsEKEGZuemg==
 
-micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5:
-  version "4.0.5"
-  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
-  integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.7:
+  version "4.0.7"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5"
+  integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==
   dependencies:
-    braces "^3.0.2"
+    braces "^3.0.3"
     picomatch "^2.3.1"
 
 mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
@@ -10465,10 +10604,10 @@ range-parser@^1.2.1, range-parser@~1.2.1:
   resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
   integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
 
-raw-body@2.5.1:
-  version "2.5.1"
-  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
-  integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
+raw-body@2.5.2:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+  integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
   dependencies:
     bytes "3.1.2"
     http-errors "2.0.0"
@@ -11837,7 +11976,14 @@ stringify-object@^3.3.0:
     is-obj "^1.0.1"
     is-regexp "^1.0.0"
 
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+  dependencies:
+    ansi-regex "^5.0.1"
+
+strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
   integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -12920,14 +13066,6 @@ void-elements@3.1.0:
   resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"
   integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==
 
-vue-template-compiler@^2.6.11:
-  version "2.7.15"
-  resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.15.tgz#ec88ba8ceafe0f17a528b89c57e01e02da92b0de"
-  integrity sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og==
-  dependencies:
-    de-indent "^1.0.2"
-    he "^1.2.0"
-
 w3c-hr-time@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
@@ -13012,9 +13150,9 @@ webidl-conversions@^6.1.0:
   integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
 
 webpack-dev-middleware@^5.3.1:
-  version "5.3.3"
-  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f"
-  integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==
+  version "5.3.4"
+  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517"
+  integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==
   dependencies:
     colorette "^2.0.10"
     memfs "^3.4.3"
@@ -13384,8 +13522,7 @@ workerpool@6.2.1:
   resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343"
   integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==
 
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
-  name wrap-ansi-cjs
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
   integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -13403,6 +13540,15 @@ wrap-ansi@^6.2.0:
     string-width "^4.1.0"
     strip-ansi "^6.0.0"
 
+wrap-ansi@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+  integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+  dependencies:
+    ansi-styles "^4.0.0"
+    string-width "^4.1.0"
+    strip-ansi "^6.0.0"
+
 wrap-ansi@^8.1.0:
   version "8.1.0"
   resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
@@ -13428,14 +13574,14 @@ write-file-atomic@^3.0.0:
     typedarray-to-buffer "^3.1.5"
 
 ws@^7.4.6:
-  version "7.5.9"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591"
-  integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
+  version "7.5.10"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9"
+  integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==
 
 ws@^8.13.0:
-  version "8.13.0"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
-  integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
+  version "8.18.0"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc"
+  integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
 
 xml-name-validator@^3.0.0:
   version "3.0.0"
diff --git a/go.mod b/go.mod
index 3bb83c63a..cd62c307a 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/kiali/kiali
 
-go 1.22.4
+go 1.22.5
 
 require (
 	github.com/NYTimes/gziphandler v1.1.1
diff --git a/kubernetes/cache/cache.go b/kubernetes/cache/cache.go
index fa319c2c1..fa4a2664d 100644
--- a/kubernetes/cache/cache.go
+++ b/kubernetes/cache/cache.go
@@ -26,8 +26,10 @@ const (
 	waypointExpirationTime     = 1 * time.Minute
 )
 
-const kialiCacheMeshKey = "mesh"
-const ztunnelApp = "ztunnel"
+const (
+	kialiCacheMeshKey = "mesh"
+	ztunnelApp        = "ztunnel"
+)
 
 // KialiCache stores both kube objects and non-kube related data such as pods' proxy status.
 // It is exclusively used by the business layer where it's expected to be a singleton.
@@ -307,6 +309,10 @@ type namespacesKey struct {
 	token   string
 }
 
+func (n namespacesKey) String() string {
+	return fmt.Sprintf("cluster: %s\ttoken: xxx", n.cluster)
+}
+
 func (c *kialiCacheImpl) GetNamespace(cluster string, token string, namespace string) (models.Namespace, bool) {
 	c.namespacesLock.RLock()
 	defer c.namespacesLock.RUnlock()
diff --git a/kubernetes/client_factory.go b/kubernetes/client_factory.go
index 40144b9f1..2ce684300 100644
--- a/kubernetes/client_factory.go
+++ b/kubernetes/client_factory.go
@@ -49,6 +49,8 @@ type clientFactory struct {
 	// "in cluster" config. This name comes from the istio cluster id.
 	homeCluster string
 
+	kialiConfig *kialiConfig.Config
+
 	// mutex for when accessing the stored clients
 	mutex sync.RWMutex
 
@@ -92,7 +94,7 @@ func getClientFactory(conf kialiConfig.Config) (*clientFactory, error) {
 		Burst:           conf.KubernetesConfig.Burst,
 	}
 
-	return newClientFactory(&baseConfig)
+	return newClientFactory(&conf, &baseConfig)
 }
 
 // NewClientFactory creates a new client factory that can be transitory.
@@ -118,8 +120,9 @@ func NewClientFactory(ctx context.Context, conf kialiConfig.Config) (ClientFacto
 
 // newClientFactory allows for specifying the config and expiry duration
 // Mock friendly for testing purposes
-func newClientFactory(restConfig *rest.Config) (*clientFactory, error) {
+func newClientFactory(conf *kialiConfig.Config, restConfig *rest.Config) (*clientFactory, error) {
 	f := &clientFactory{
+		kialiConfig:     conf,
 		baseRestConfig:  restConfig,
 		clientEntries:   make(map[string]map[string]ClientInterface),
 		recycleChan:     make(chan string),
@@ -179,40 +182,22 @@ func (cf *clientFactory) newClient(authInfo *api.AuthInfo, expirationTime time.D
 	// So, if OpenID strategy is active, check if a proxy is configured.
 	// If there is, use it UNLESS the token is the one of the Kiali SA. If
 	// the token is the one of the Kiali SA, the proxy can be bypassed.
-	cfg := kialiConfig.Get()
-	if cfg.Auth.Strategy == kialiConfig.AuthStrategyOpenId && cfg.Auth.OpenId.ApiProxy != "" && cfg.Auth.OpenId.ApiProxyCAData != "" {
-
-		var kialiToken string
-		var err error
-
-		if cluster == cf.homeCluster {
-			kialiToken, _, err = GetKialiTokenForHomeCluster()
-		} else {
-			kialiToken, err = cf.GetSAClient(cluster).GetToken(), nil
-		}
-
+	if cf.kialiConfig.Auth.Strategy == kialiConfig.AuthStrategyOpenId && cf.kialiConfig.Auth.OpenId.ApiProxy != "" && cf.kialiConfig.Auth.OpenId.ApiProxyCAData != "" {
+		// Override the CA data on the client with the proxy CA from the Kiali config.
+		caData := cf.kialiConfig.Auth.OpenId.ApiProxyCAData
+		rootCaDecoded, err := base64.StdEncoding.DecodeString(caData)
 		if err != nil {
 			return nil, err
 		}
 
-		// User token and not Kiali SA token so use the proxy.
-		if kialiToken != authInfo.Token {
-			// Override the CA data on the client with the proxy CA from the Kiali config.
-			caData := cfg.Auth.OpenId.ApiProxyCAData
-			rootCaDecoded, err := base64.StdEncoding.DecodeString(caData)
-			if err != nil {
-				return nil, err
-			}
-
-			config.TLSClientConfig = rest.TLSClientConfig{
-				CAData: []byte(rootCaDecoded),
-			}
-			config.Host = cfg.Auth.OpenId.ApiProxy
+		config.TLSClientConfig = rest.TLSClientConfig{
+			CAData: []byte(rootCaDecoded),
 		}
+		config.Host = cf.kialiConfig.Auth.OpenId.ApiProxy
 	}
 
 	// Impersonation is valid only for header authentication strategy
-	if cfg.Auth.Strategy == kialiConfig.AuthStrategyHeader && authInfo.Impersonate != "" {
+	if cf.kialiConfig.Auth.Strategy == kialiConfig.AuthStrategyHeader && authInfo.Impersonate != "" {
 		config.Impersonate.UserName = authInfo.Impersonate
 		config.Impersonate.Groups = authInfo.ImpersonateGroups
 		config.Impersonate.Extra = authInfo.ImpersonateUserExtra
@@ -246,13 +231,8 @@ func (cf *clientFactory) newClient(authInfo *api.AuthInfo, expirationTime time.D
 		}
 
 		// Replace the Kiali SA token with the user's auth token.
-		// Only if we are not in an anonymous mode
-		// and if we don't use OpenID with RBAC is disable.
-		if !(cfg.Auth.Strategy == kialiConfig.AuthStrategyAnonymous) &&
-			!(cfg.Auth.Strategy == kialiConfig.AuthStrategyOpenId && cfg.Auth.OpenId.DisableRBAC) {
-			remoteConfig.BearerToken = authInfo.Token
-			remoteConfig.BearerTokenFile = ""
-		}
+		remoteConfig.BearerToken = authInfo.Token
+		remoteConfig.BearerTokenFile = ""
 
 		newClient, err = newClientWithRemoteClusterInfo(remoteConfig, &clusterInfo)
 		if err != nil {
@@ -296,11 +276,19 @@ func (cf *clientFactory) GetSAClients() map[string]ClientInterface {
 
 // getClient returns a client for the specified token. Creating one if necessary.
 func (cf *clientFactory) GetClient(authInfo *api.AuthInfo, cluster string) (ClientInterface, error) {
+	if cf.kialiConfig.IsRBACDisabled() {
+		return cf.GetSAClient(cluster), nil
+	}
+
 	return cf.getRecycleClient(authInfo, defaultExpirationTime, cluster)
 }
 
 // getClient returns a client for the specified token. Creating one if necessary.
 func (cf *clientFactory) GetClients(authInfos map[string]*api.AuthInfo) (map[string]ClientInterface, error) {
+	if cf.kialiConfig.IsRBACDisabled() {
+		return cf.GetSAClients(), nil
+	}
+
 	clients := make(map[string]ClientInterface)
 	for cluster, authInfo := range authInfos {
 		ci, err := cf.getRecycleClient(authInfo, defaultExpirationTime, cluster)
diff --git a/store/expiration_store.go b/store/expiration_store.go
index fdd80ba96..0f00e98d4 100644
--- a/store/expiration_store.go
+++ b/store/expiration_store.go
@@ -90,7 +90,7 @@ func (s *ExpirationStore[K, V]) checkAndRemoveExpiredKeys(ctx context.Context) <
 					}
 
 					if time.Now().After(expiration) {
-						log.Tracef("Key %v expired. Removing from store", key)
+						log.Tracef("Key '%v' expired. Removing from store", key)
 						s.Remove(key)
 					}
 				}


Test patch:
diff --git a/config/config_test.go b/config/config_test.go
index 16e0dc23d..85fd4cfd7 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -11,6 +11,7 @@ import (
 	"github.com/kiali/kiali/util"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestSecretFileOverrides(t *testing.T) {
@@ -366,3 +367,63 @@ func TestValidateAuthStrategy(t *testing.T) {
 		}
 	}
 }
+
+func TestIsRBACDisabled(t *testing.T) {
+	cases := map[string]struct {
+		authConfig         AuthConfig
+		expectRBACDisabled bool
+	}{
+		"anonymous should have RBAC disabled": {
+			authConfig: AuthConfig{
+				Strategy: AuthStrategyAnonymous,
+			},
+			expectRBACDisabled: true,
+		},
+		"openid with rbac disabled should have RBAC disabled": {
+			authConfig: AuthConfig{
+				Strategy: AuthStrategyOpenId,
+				OpenId: OpenIdConfig{
+					DisableRBAC: true,
+				},
+			},
+			expectRBACDisabled: true,
+		},
+		"openid with rbac enabled should have RBAC enabled": {
+			authConfig: AuthConfig{
+				Strategy: AuthStrategyOpenId,
+				OpenId: OpenIdConfig{
+					DisableRBAC: false,
+				},
+			},
+			expectRBACDisabled: false,
+		},
+		"openshift should have RBAC enabled": {
+			authConfig: AuthConfig{
+				Strategy: AuthStrategyOpenshift,
+			},
+			expectRBACDisabled: false,
+		},
+		"token should have RBAC enabled": {
+			authConfig: AuthConfig{
+				Strategy: AuthStrategyToken,
+			},
+			expectRBACDisabled: false,
+		},
+		"header should have RBAC enabled": {
+			authConfig: AuthConfig{
+				Strategy: AuthStrategyHeader,
+			},
+			expectRBACDisabled: false,
+		},
+	}
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			require := require.New(t)
+
+			conf := NewConfig()
+			conf.Auth = tc.authConfig
+
+			require.Equal(tc.expectRBACDisabled, conf.IsRBACDisabled())
+		})
+	}
+}
diff --git a/kubernetes/client_factory_test.go b/kubernetes/client_factory_test.go
index 3692bf18e..b6ba74974 100644
--- a/kubernetes/client_factory_test.go
+++ b/kubernetes/client_factory_test.go
@@ -114,6 +114,7 @@ func TestConcurrentClientExpiration(t *testing.T) {
 // TestConcurrentClientFactory test Concurrently create ClientFactory
 func TestConcurrentClientFactory(t *testing.T) {
 	require := require.New(t)
+	conf := config.NewConfig()
 	istioConfig := rest.Config{}
 	count := 100
 
@@ -125,7 +126,7 @@ func TestConcurrentClientFactory(t *testing.T) {
 	for i := 0; i < count; i++ {
 		go func() {
 			defer wg.Done()
-			_, err := newClientFactory(&istioConfig)
+			_, err := newClientFactory(conf, &istioConfig)
 			require.NoError(err)
 		}()
 	}
@@ -387,39 +388,73 @@ func setGlobalKialiSAToken(t *testing.T) {
 }
 
 func TestClientCreatedWithProxyInfo(t *testing.T) {
-	require := require.New(t)
-
-	cfg := config.NewConfig()
-	cfg.Deployment.RemoteSecretPath = t.TempDir() // Random dir so that the remote secret isn't read if it exists.
-	cfg.Auth.Strategy = config.AuthStrategyOpenId
-	cfg.Auth.OpenId.ApiProxyCAData = base64.StdEncoding.EncodeToString(proxyCAData)
-	cfg.Auth.OpenId.ApiProxy = "https://api-proxy:8443"
-	SetConfig(t, *cfg)
-
-	clientFactory := NewTestingClientFactory(t)
+	cases := map[string]struct {
+		auth              config.AuthConfig
+		expectProxyConfig bool
+	}{
+		"openid with proxy defined should have proxy on client": {
+			auth: config.AuthConfig{
+				Strategy: config.AuthStrategyOpenId,
+				OpenId: config.OpenIdConfig{
+					ApiProxy:       "https://api-proxy:8443",
+					ApiProxyCAData: base64.StdEncoding.EncodeToString(proxyCAData),
+				},
+			},
+			expectProxyConfig: true,
+		},
+		"openid with rbac disabled and proxy defined should not have proxy on client": {
+			auth: config.AuthConfig{
+				Strategy: config.AuthStrategyOpenId,
+				OpenId: config.OpenIdConfig{
+					DisableRBAC:    true,
+					ApiProxy:       "https://api-proxy:8443",
+					ApiProxyCAData: base64.StdEncoding.EncodeToString(proxyCAData),
+				},
+			},
+			expectProxyConfig: false,
+		},
+		"anonymous with proxy defined should not have proxy on client": {
+			auth: config.AuthConfig{
+				Strategy: config.AuthStrategyAnonymous,
+				OpenId: config.OpenIdConfig{
+					DisableRBAC:    true,
+					ApiProxy:       "https://api-proxy:8443",
+					ApiProxyCAData: base64.StdEncoding.EncodeToString(proxyCAData),
+				},
+			},
+			expectProxyConfig: false,
+		},
+	}
 
-	// Regular clients should have the proxy info
-	client, err := clientFactory.GetClient(api.NewAuthInfo(), cfg.KubernetesConfig.ClusterName)
-	require.NoError(err)
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			require := require.New(t)
 
-	require.Equal(cfg.Auth.OpenId.ApiProxy, client.ClusterInfo().ClientConfig.Host)
-	require.Equal(proxyCAData, client.ClusterInfo().ClientConfig.CAData)
+			cfg := config.NewConfig()
+			cfg.Deployment.RemoteSecretPath = t.TempDir() // Random dir so that the remote secret isn't read if it exists.
+			cfg.Auth = tc.auth
+			SetConfig(t, *cfg)
 
-	// Service account clients should not have the proxy info.
-	// Two ways to get a SA client: 1. GetClient with SA token and 2. GetSAClient
-	setGlobalKialiSAToken(t)
-	authInfo := api.NewAuthInfo()
-	authInfo.Token = KialiTokenForHomeCluster
+			clientFactory := NewTestingClientFactory(t)
 
-	client, err = clientFactory.GetClient(authInfo, cfg.KubernetesConfig.ClusterName)
-	require.NoError(err)
+			// Regular clients should have the proxy info
+			client, err := clientFactory.GetClient(api.NewAuthInfo(), cfg.KubernetesConfig.ClusterName)
+			require.NoError(err)
 
-	require.NotEqual(cfg.Auth.OpenId.ApiProxy, client.ClusterInfo().ClientConfig.Host)
-	require.NotEqual(proxyCAData, client.ClusterInfo().ClientConfig.CAData)
+			if tc.expectProxyConfig {
+				require.Equal(cfg.Auth.OpenId.ApiProxy, client.ClusterInfo().ClientConfig.Host)
+				require.Equal(proxyCAData, client.ClusterInfo().ClientConfig.CAData)
+			} else {
+				require.NotEqual(cfg.Auth.OpenId.ApiProxy, client.ClusterInfo().ClientConfig.Host)
+				require.NotEqual(proxyCAData, client.ClusterInfo().ClientConfig.CAData)
+			}
 
-	client = clientFactory.GetSAClient(cfg.KubernetesConfig.ClusterName)
-	require.NotEqual(cfg.Auth.OpenId.ApiProxy, client.ClusterInfo().ClientConfig.Host)
-	require.NotEqual(proxyCAData, client.ClusterInfo().ClientConfig.CAData)
+			// Service account clients should not have the proxy info.
+			client = clientFactory.GetSAClient(cfg.KubernetesConfig.ClusterName)
+			require.NotEqual(cfg.Auth.OpenId.ApiProxy, client.ClusterInfo().ClientConfig.Host)
+			require.NotEqual(proxyCAData, client.ClusterInfo().ClientConfig.CAData)
+		})
+	}
 }
 
 func TestNewClientFactoryClosesRecycleWhenCTXCancelled(t *testing.T) {
@@ -506,3 +541,69 @@ func TestClientFactoryReturnsSAClientWhenConfigClusterNameIsEmpty(t *testing.T)
 
 	require.NotNil(clientFactory.GetSAHomeClusterClient())
 }
+
+func TestClientFactoryGetClients(t *testing.T) {
+	cases := map[string]struct {
+		auth               config.AuthConfig
+		authInfo           map[string]*api.AuthInfo
+		expectClientsEqual bool
+	}{
+		"anonymous strategy returns Service Account clients": {
+			auth: config.AuthConfig{
+				Strategy: config.AuthStrategyAnonymous,
+			},
+			authInfo:           map[string]*api.AuthInfo{"cluster1": api.NewAuthInfo()},
+			expectClientsEqual: true,
+		},
+		"anonymous strategy returns Service Account clients with nil auth info": {
+			auth: config.AuthConfig{
+				Strategy: config.AuthStrategyAnonymous,
+			},
+			authInfo:           nil,
+			expectClientsEqual: true,
+		},
+		"openid with rbac disabled returns Service Account clients": {
+			auth: config.AuthConfig{
+				Strategy: config.AuthStrategyOpenId,
+				OpenId: config.OpenIdConfig{
+					DisableRBAC: true,
+				},
+			},
+			authInfo:           map[string]*api.AuthInfo{"cluster1": api.NewAuthInfo()},
+			expectClientsEqual: true,
+		},
+		"openid with rbac enabled returns user clients": {
+			auth: config.AuthConfig{
+				Strategy: config.AuthStrategyOpenId,
+				OpenId: config.OpenIdConfig{
+					DisableRBAC: false,
+				},
+			},
+			authInfo:           map[string]*api.AuthInfo{"cluster1": api.NewAuthInfo()},
+			expectClientsEqual: false,
+		},
+	}
+	for name, tc := range cases {
+		t.Run(name, func(t *testing.T) {
+			require := require.New(t)
+			conf := config.NewConfig()
+			conf.Auth = tc.auth
+			conf.KubernetesConfig.ClusterName = "cluster1"
+			SetConfig(t, *conf)
+
+			clientFactory := NewTestingClientFactory(t)
+			clients, err := clientFactory.GetClients(tc.authInfo)
+			require.NoError(err)
+			require.Len(clients, 1)
+
+			saClients := clientFactory.GetSAClients()
+			require.Len(saClients, 1)
+
+			if tc.expectClientsEqual {
+				require.Equal(clients["cluster1"], saClients["cluster1"])
+			} else {
+				require.NotEqual(clients["cluster1"], saClients["cluster1"])
+			}
+		})
+	}
+}
diff --git a/kubernetes/testing.go b/kubernetes/testing.go
index c86456d6c..1bd58dfa6 100644
--- a/kubernetes/testing.go
+++ b/kubernetes/testing.go
@@ -56,7 +56,7 @@ func NewTestingClientFactory(t *testing.T) *clientFactory {
 	}
 
 	clientConfig := rest.Config{}
-	client, err := newClientFactory(&clientConfig)
+	client, err := newClientFactory(config.Get(), &clientConfig)
 	if err != nil {
 		t.Fatalf("Error creating client factory: %v", err)
 	}