Canvas: Expose ingress auth details

Change-Id: I337163f5919db5c8e48d6d429dcdc6420b196d3d
diff --git a/apps/canvas/front/package-lock.json b/apps/canvas/front/package-lock.json
index 867e8c6..39c0823 100644
--- a/apps/canvas/front/package-lock.json
+++ b/apps/canvas/front/package-lock.json
@@ -10,6 +10,7 @@
       "dependencies": {
         "@hookform/resolvers": "^3.9.1",
         "@radix-ui/react-accordion": "^1.2.1",
+        "@radix-ui/react-checkbox": "^1.3.1",
         "@radix-ui/react-collapsible": "^1.1.1",
         "@radix-ui/react-dialog": "^1.1.2",
         "@radix-ui/react-icons": "^1.3.1",
@@ -1090,6 +1091,193 @@
         }
       }
     },
+    "node_modules/@radix-ui/react-checkbox": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.1.tgz",
+      "integrity": "sha512-xTaLKAO+XXMPK/BpVTSaAAhlefmvMSACjIhK9mGsImvX2ljcTDm8VGR1CuS1uYcNdR5J+oiOhoJZc5un6bh3VQ==",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.2",
+        "@radix-ui/react-compose-refs": "1.1.2",
+        "@radix-ui/react-context": "1.1.2",
+        "@radix-ui/react-presence": "1.1.4",
+        "@radix-ui/react-primitive": "2.1.2",
+        "@radix-ui/react-use-controllable-state": "1.2.2",
+        "@radix-ui/react-use-previous": "1.1.1",
+        "@radix-ui/react-use-size": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/primitive": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
+      "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-compose-refs": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+      "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-context": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+      "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-presence": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
+      "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.2",
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-primitive": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.2.tgz",
+      "integrity": "sha512-uHa+l/lKfxuDD2zjN/0peM/RhhSmRjr5YWdk/37EnSv1nJ88uvG85DPexSm8HdFQROd2VdERJ6ynXbkCFi+APw==",
+      "dependencies": {
+        "@radix-ui/react-slot": "1.2.2"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-slot": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.2.tgz",
+      "integrity": "sha512-y7TBO4xN4Y94FvcWIOIh18fM4R1A8S4q1jhoz4PNzOoHsFcN8pogcFmZrTYAm4F9VRUrWP/Mw7xSKybIeRI+CQ==",
+      "dependencies": {
+        "@radix-ui/react-compose-refs": "1.1.2"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-controllable-state": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+      "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+      "dependencies": {
+        "@radix-ui/react-use-effect-event": "0.0.2",
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-layout-effect": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+      "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-previous": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
+      "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-checkbox/node_modules/@radix-ui/react-use-size": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
+      "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@radix-ui/react-collapsible": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.1.tgz",
@@ -1776,6 +1964,37 @@
         }
       }
     },
+    "node_modules/@radix-ui/react-use-effect-event": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+      "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+      "dependencies": {
+        "@radix-ui/react-use-layout-effect": "1.1.1"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+      "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+      "peerDependencies": {
+        "@types/react": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@radix-ui/react-use-escape-keydown": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
diff --git a/apps/canvas/front/package.json b/apps/canvas/front/package.json
index 9eefaff..4c9ba0c 100644
--- a/apps/canvas/front/package.json
+++ b/apps/canvas/front/package.json
@@ -16,6 +16,7 @@
   "dependencies": {
     "@hookform/resolvers": "^3.9.1",
     "@radix-ui/react-accordion": "^1.2.1",
+    "@radix-ui/react-checkbox": "^1.3.1",
     "@radix-ui/react-collapsible": "^1.1.1",
     "@radix-ui/react-dialog": "^1.1.2",
     "@radix-ui/react-icons": "^1.3.1",
diff --git a/apps/canvas/front/src/components/node-gateway-https.tsx b/apps/canvas/front/src/components/node-gateway-https.tsx
index 1397f5c..e618943 100644
--- a/apps/canvas/front/src/components/node-gateway-https.tsx
+++ b/apps/canvas/front/src/components/node-gateway-https.tsx
@@ -2,13 +2,17 @@
 import { useStateStore, AppNode, GatewayHttpsNode, ServiceNode, nodeLabel, useEnv, nodeIsConnectable } from '@/lib/state';
 import { Handle, Position, useNodes } from '@xyflow/react';
 import { NodeRect } from './node-rect';
-import { useEffect, useMemo } from 'react';
+import { useCallback, useEffect, useMemo } from 'react';
 import { z } from "zod";
 import { zodResolver } from "@hookform/resolvers/zod";
 import { useForm, EventType, DeepPartial } from 'react-hook-form';
 import { Form, FormControl, FormField, FormItem, FormMessage } from './ui/form';
 import { Input } from './ui/input';
 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select';
+import { Checkbox } from "./ui/checkbox";
+import { Label } from "./ui/label";
+import { Button } from "./ui/button";
+import { XIcon } from "lucide-react";
 
 const schema = z.object({
   network: z.string().min(1, "reqired"),
@@ -20,6 +24,18 @@
   portId: z.string(),
 });
 
+const authEnabledSchema = z.object({
+  enabled: z.boolean(),
+});
+
+const authGroupSchema = z.object({
+  group: z.string(),
+});
+
+const authNoAuthPatternSchema = z.object({
+  noAuthPathPattern: z.string(),
+});
+
 export function NodeGatewayHttps(node: GatewayHttpsNode) {
   const { id, selected } = node;
   const isConnectableNetwork = useMemo(() => nodeIsConnectable(node, "subdomain"), [node]);
@@ -29,19 +45,19 @@
       {nodeLabel(node)}
       <Handle
         type={"source"}
-        id="subdomain" 
+        id="subdomain"
         position={Position.Top}
         isConnectable={isConnectableNetwork}
-        isConnectableStart={isConnectableNetwork} 
-        isConnectableEnd={isConnectableNetwork} 
+        isConnectableStart={isConnectableNetwork}
+        isConnectableEnd={isConnectableNetwork}
       />
       <Handle
         type={"target"}
-        id="https" 
+        id="https"
         position={Position.Bottom}
         isConnectable={isConnectable}
-        isConnectableStart={isConnectable} 
-        isConnectableEnd={isConnectable} 
+        isConnectableStart={isConnectable}
+        isConnectableEnd={isConnectable}
       />
     </NodeRect>
   );
@@ -64,7 +80,6 @@
         let edges = store.edges;
         if (data.network !== undefined) {
           edges = edges.filter((e) => {
-            console.log(e);
             if (e.source === id && e.sourceHandle === "subdomain" && e.target === data.network && e.targetHandle === "subdomain") {
               return false;
             } else {
@@ -127,7 +142,6 @@
   }, [nodes, selected]);
   useEffect(() => {
     const sub = connectedToForm.watch((value: DeepPartial<z.infer<typeof connectedToSchema>>, { name, type }: { name?: keyof z.infer<typeof connectedToSchema> | undefined, type?: EventType | undefined }) => {
-      console.log({ name, type });
       if (type !== "change") {
         return;
       }
@@ -157,11 +171,86 @@
     });
     return () => sub.unsubscribe();
   }, [connectedToForm, store, selectable]);
+  const authEnabledForm = useForm<z.infer<typeof authEnabledSchema>>({
+    resolver: zodResolver(authEnabledSchema),
+    mode: "onChange",
+    defaultValues: {
+      enabled: data.auth ? data.auth.enabled : false,
+    },
+  });
+  const authGroupForm = useForm<z.infer<typeof authGroupSchema>>({
+    resolver: zodResolver(authGroupSchema),
+    mode: "onSubmit",
+    defaultValues: {
+      group: "",
+    },
+  }); const authNoAuthPatternFrom = useForm<z.infer<typeof authNoAuthPatternSchema>>({
+    resolver: zodResolver(authNoAuthPatternSchema),
+    mode: "onChange",
+    defaultValues: {
+      noAuthPathPattern: "",
+    },
+  });
+  useEffect(() => {
+    const sub = authEnabledForm.watch((value, { name }) => {
+      if (name === "enabled") {
+        store.updateNodeData<"gateway-https">(id, {
+          auth: {
+            ...data.auth,
+            enabled: value.enabled,
+          }
+        })
+      }
+    });
+    return () => sub.unsubscribe();
+  }, [id, data, authEnabledForm, store]);
+  const removeGroup = useCallback((group: string) => {
+    const groups = data?.auth?.groups || [];
+    store.updateNodeData<"gateway-https">(id, {
+      auth: {
+        ...data.auth,
+        groups: groups.filter((g) => g !== group),
+      },
+    });
+    return true;
+  }, [id, data, store]);
+  const onGroupSubmit = useCallback((values: z.infer<typeof authGroupSchema>) => {
+    const groups = data.auth?.groups || [];
+    groups.push(values.group)
+    store.updateNodeData<"gateway-https">(id, {
+      auth: {
+        ...data.auth,
+        groups,
+      },
+    });
+    authGroupForm.reset();
+  }, [id, data, store]);
+  const removeNoAuthPathPattern = useCallback((path: string) => {
+    const noAuthPathPatterns = data?.auth?.noAuthPathPatterns || [];
+    store.updateNodeData<"gateway-https">(id, {
+      auth: {
+        ...data.auth,
+        noAuthPathPatterns: noAuthPathPatterns.filter((p) => p !== path),
+      },
+    });
+    return true;
+  }, [id, data, store]);
+  const onNoAuthPathPatternSubmit = useCallback((values: z.infer<typeof authNoAuthPatternSchema>) => {
+    const noAuthPathPatterns = data.auth?.noAuthPathPatterns || [];
+    noAuthPathPatterns.push(values.noAuthPathPattern)
+    store.updateNodeData<"gateway-https">(id, {
+      auth: {
+        ...data.auth,
+        noAuthPathPatterns,
+      },
+    });
+    authNoAuthPatternFrom.reset();
+  }, [id, data, store]);
   return (
     <>
       <Form {...form}>
         <form className="space-y-2">
-          <FormField 
+          <FormField
             control={form.control}
             name="network"
             render={({ field }) => (
@@ -182,7 +271,7 @@
               </FormItem>
             )}
           />
-          <FormField 
+          <FormField
             control={form.control}
             name="subdomain"
             render={({ field }) => (
@@ -198,7 +287,7 @@
       </Form>
       <Form {...connectedToForm}>
         <form className="space-y-2">
-        <FormField
+          <FormField
             control={connectedToForm.control}
             name="id"
             render={({ field }) => (
@@ -219,7 +308,7 @@
               </FormItem>
             )}
           />
-          <FormField 
+          <FormField
             control={connectedToForm.control}
             name="portId"
             render={({ field }) => (
@@ -237,11 +326,73 @@
                   </SelectContent>
                 </Select>
                 <FormMessage />
-              </FormItem>           
+              </FormItem>
             )}
           />
         </form>
       </Form>
+      Auth
+      <Form {...authEnabledForm}>
+        <form className="space-y-2">
+          <FormField
+            control={authEnabledForm.control}
+            name="enabled"
+            render={({ field }) => (
+              <FormItem>
+                <Checkbox id="authEnabled" onCheckedChange={field.onChange} checked={field.value} />
+                <Label htmlFor="authEnabled">Enabled</Label>
+                <FormMessage />
+              </FormItem>
+            )}
+          />
+        </form>
+      </Form>
+      {data && data.auth && data.auth.enabled ? (
+        <>
+          Authorized Groups
+          <ul>
+            {(data.auth.groups || []).map((p) => (<li key={p}><Button size={"icon"} variant={"ghost"} onClick={() => removeGroup(p)}><XIcon /></Button> {p}</li>))}
+          </ul>
+          <Form {...authGroupForm}>
+            <form className="flex flex-row space-x-1" onSubmit={authGroupForm.handleSubmit(onGroupSubmit)}>
+              <FormField
+                control={authGroupForm.control}
+                name="group"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormControl>
+                      <Input placeholder="group" className="border border-black" {...field} />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+              <Button type="submit">Add Group</Button>
+            </form>
+          </Form>
+          Auth optional path patterns
+          <ul>
+            {(data.auth.noAuthPathPatterns || []).map((p) => (<li key={p}><Button size={"icon"} variant={"ghost"} onClick={() => removeNoAuthPathPattern(p)}><XIcon /></Button> {p}</li>))}
+          </ul>
+          <Form {...authNoAuthPatternFrom}>
+            <form className="flex flex-row space-x-1" onSubmit={authNoAuthPatternFrom.handleSubmit(onNoAuthPathPatternSubmit)}>
+              <FormField
+                control={authNoAuthPatternFrom.control}
+                name="noAuthPathPattern"
+                render={({ field }) => (
+                  <FormItem>
+                    <FormControl>
+                      <Input placeholder="group" className="border border-black" {...field} />
+                    </FormControl>
+                    <FormMessage />
+                  </FormItem>
+                )}
+              />
+              <Button type="submit">Add</Button>
+            </form>
+          </Form>
+        </>
+      ) : (<></>)}
     </>
   );
 }
\ No newline at end of file
diff --git a/apps/canvas/front/src/components/ui/checkbox.tsx b/apps/canvas/front/src/components/ui/checkbox.tsx
new file mode 100644
index 0000000..8d02b28
--- /dev/null
+++ b/apps/canvas/front/src/components/ui/checkbox.tsx
@@ -0,0 +1,27 @@
+import * as React from "react"
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
+import { cn } from "@/lib/utils"
+import { CheckIcon } from "@radix-ui/react-icons"
+
+const Checkbox = React.forwardRef<
+  React.ElementRef<typeof CheckboxPrimitive.Root>,
+  React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
+>(({ className, ...props }, ref) => (
+  <CheckboxPrimitive.Root
+    ref={ref}
+    className={cn(
+      "peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
+      className
+    )}
+    {...props}
+  >
+    <CheckboxPrimitive.Indicator
+      className={cn("flex items-center justify-center text-current")}
+    >
+      <CheckIcon className="h-4 w-4" />
+    </CheckboxPrimitive.Indicator>
+  </CheckboxPrimitive.Root>
+))
+Checkbox.displayName = CheckboxPrimitive.Root.displayName
+
+export { Checkbox }
diff --git a/apps/canvas/front/src/lib/config.ts b/apps/canvas/front/src/lib/config.ts
index 22353f8..d6646c9 100644
--- a/apps/canvas/front/src/lib/config.ts
+++ b/apps/canvas/front/src/lib/config.ts
@@ -121,7 +121,13 @@
                         port: {
                             name: n.data.ports.find((p) => p.id === i.data.https!.portId)!.name,
                         },
-                        auth: { enabled: false },
+                        auth: (i.data.auth?.enabled || false ? {
+                            enabled: true,
+                            groups: i.data.auth!.groups,
+                            noAuthPathPatterns: i.data.auth!.noAuthPathPatterns,
+                        } : {
+                            enabled: false,
+                        }),
                     })),
                     expose: findExpose(n),
                     preBuildCommands: n.data.preBuildCommands ? n.data.preBuildCommands.split("\n").map((cmd) => ({ bin: cmd })) : [],
diff --git a/apps/canvas/front/src/lib/state.ts b/apps/canvas/front/src/lib/state.ts
index ee6f6d2..02fd983 100644
--- a/apps/canvas/front/src/lib/state.ts
+++ b/apps/canvas/front/src/lib/state.ts
@@ -41,6 +41,11 @@
   network?: string;
   subdomain?: string;
   https?: PortConnectedTo;
+  auth?: {
+    enabled: boolean;
+    groups: string[];
+    noAuthPathPatterns: string[];
+  }
 };
 
 export type GatewayHttpsNode = Node<GatewayHttpsData> & {