diff --git a/README.md b/README.md
index 0727c935..545b36ba 100644
--- a/README.md
+++ b/README.md
@@ -86,6 +86,15 @@ Flowise has 3 different modules in a single mono repository.
Any code changes will reload the app automatically on [http://localhost:8080](http://localhost:8080)
+## 🔒 Authentication
+
+To enable app level authentication, add `USERNAME` and `PASSWORD` to the `.env` file in `packages/server`:
+
+```
+USERNAME=user
+PASSWORD=1234
+```
+
## 📖 Documentation
Coming soon
diff --git a/packages/server/.env.example b/packages/server/.env.example
index 2fc80e3a..18f8efd2 100644
--- a/packages/server/.env.example
+++ b/packages/server/.env.example
@@ -1 +1,3 @@
PORT=3000
+# USERNAME=user
+# PASSWORD=1234
\ No newline at end of file
diff --git a/packages/server/README.md b/packages/server/README.md
index a7696c6f..1915863b 100644
--- a/packages/server/README.md
+++ b/packages/server/README.md
@@ -20,6 +20,15 @@ Drag & drop UI to build your customized LLM flow using [LangchainJS](https://git
3. Open [http://localhost:3000](http://localhost:3000)
+## 🔒 Authentication
+
+To enable app level authentication, add `USERNAME` and `PASSWORD` to the `.env` file:
+
+```
+USERNAME=user
+PASSWORD=1234
+```
+
## 📖 Documentation
Coming Soon
diff --git a/packages/server/package.json b/packages/server/package.json
index 2886e6e8..0a551112 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -51,6 +51,7 @@
"cors": "^2.8.5",
"dotenv": "^16.0.0",
"express": "^4.17.3",
+ "express-basic-auth": "^1.2.1",
"flowise-components": "*",
"flowise-ui": "*",
"moment-timezone": "^0.5.34",
diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts
index 9dedaf5e..57601a16 100644
--- a/packages/server/src/index.ts
+++ b/packages/server/src/index.ts
@@ -4,6 +4,7 @@ import path from 'path'
import cors from 'cors'
import http from 'http'
import * as fs from 'fs'
+import basicAuth from 'express-basic-auth'
import { IChatFlow, IncomingInput, IReactFlowNode, IReactFlowObject, INodeData } from './Interface'
import {
@@ -69,6 +70,18 @@ export class App {
// Allow access from *
this.app.use(cors())
+ if (process.env.USERNAME && process.env.PASSWORD) {
+ const username = process.env.USERNAME.toLocaleLowerCase()
+ const password = process.env.PASSWORD.toLocaleLowerCase()
+ const basicAuthMiddleware = basicAuth({
+ users: { [username]: password }
+ })
+ const whitelistURLs = ['static', 'favicon', '/api/v1/prediction/', '/api/v1/node-icon/']
+ this.app.use((req, res, next) =>
+ whitelistURLs.some((url) => req.url.includes(url)) || req.url === '/' ? next() : basicAuthMiddleware(req, res, next)
+ )
+ }
+
const upload = multer({ dest: `${path.join(__dirname, '..', 'uploads')}/` })
// ----------------------------------------
diff --git a/packages/ui/src/api/client.js b/packages/ui/src/api/client.js
index 1211d67e..cafdf0b3 100644
--- a/packages/ui/src/api/client.js
+++ b/packages/ui/src/api/client.js
@@ -8,4 +8,18 @@ const apiClient = axios.create({
}
})
+apiClient.interceptors.request.use(function (config) {
+ const username = localStorage.getItem('username')
+ const password = localStorage.getItem('password')
+
+ if (username && password) {
+ config.auth = {
+ username: username.toLocaleLowerCase(),
+ password: password.toLocaleLowerCase()
+ }
+ }
+
+ return config
+})
+
export default apiClient
diff --git a/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.css b/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.css
new file mode 100644
index 00000000..f6be27ab
--- /dev/null
+++ b/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.css
@@ -0,0 +1,6 @@
+.ps__rail-x {
+ display: none !important;
+}
+.ps__thumb-x {
+ display: none !important;
+}
diff --git a/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.js b/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.js
new file mode 100644
index 00000000..c0fa8807
--- /dev/null
+++ b/packages/ui/src/layout/MainLayout/Header/ProfileSection/index.js
@@ -0,0 +1,163 @@
+import { useState, useRef, useEffect } from 'react'
+
+import PropTypes from 'prop-types'
+
+import { useSelector } from 'react-redux'
+
+// material-ui
+import { useTheme } from '@mui/material/styles'
+import {
+ Box,
+ ButtonBase,
+ Avatar,
+ ClickAwayListener,
+ Divider,
+ List,
+ ListItemButton,
+ ListItemIcon,
+ ListItemText,
+ Paper,
+ Popper,
+ Typography
+} from '@mui/material'
+
+// third-party
+import PerfectScrollbar from 'react-perfect-scrollbar'
+
+// project imports
+import MainCard from 'ui-component/cards/MainCard'
+import Transitions from 'ui-component/extended/Transitions'
+
+// assets
+import { IconLogout, IconSettings } from '@tabler/icons'
+
+import './index.css'
+
+// ==============================|| PROFILE MENU ||============================== //
+
+const ProfileSection = ({ username, handleLogout }) => {
+ const theme = useTheme()
+
+ const customization = useSelector((state) => state.customization)
+
+ const [open, setOpen] = useState(false)
+
+ const anchorRef = useRef(null)
+
+ const handleClose = (event) => {
+ if (anchorRef.current && anchorRef.current.contains(event.target)) {
+ return
+ }
+ setOpen(false)
+ }
+
+ const handleToggle = () => {
+ setOpen((prevOpen) => !prevOpen)
+ }
+
+ const prevOpen = useRef(open)
+ useEffect(() => {
+ if (prevOpen.current === true && open === false) {
+ anchorRef.current.focus()
+ }
+
+ prevOpen.current = open
+ }, [open])
+
+ return (
+ <>
+
+
+