diff --git a/docker/.env.example b/docker/.env.example
index 7bb07ebef73da303d69d0458890ed7f40941b7ed..2f6f896b0fca0c1519aa8d2ddb49b8343b2e064f 100644
--- a/docker/.env.example
+++ b/docker/.env.example
@@ -291,4 +291,8 @@ GID='1000'
 
 # Disable viewing chat history from the UI and frontend APIs.
 # See https://docs.anythingllm.com/configuration#disable-view-chat-history for more information.
-# DISABLE_VIEW_CHAT_HISTORY=1
\ No newline at end of file
+# DISABLE_VIEW_CHAT_HISTORY=1
+
+# Enable simple SSO passthrough to pre-authenticate users from a third party service.
+# See https://docs.anythingllm.com/configuration#simple-sso-passthrough for more information.
+# SIMPLE_SSO_ENABLED=1
\ No newline at end of file
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index cb3bac7f719e25f08edf77332c45ccbd5bc5d3ba..6ce42fadbdfddaf0593448cb6cc328a10e9832e8 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -9,6 +9,7 @@ import PrivateRoute, {
 import { ToastContainer } from "react-toastify";
 import "react-toastify/dist/ReactToastify.css";
 import Login from "@/pages/Login";
+import SimpleSSOPassthrough from "@/pages/Login/SSO/simple";
 import OnboardingFlow from "@/pages/OnboardingFlow";
 import i18n from "./i18n";
 
@@ -77,6 +78,8 @@ export default function App() {
               <Routes>
                 <Route path="/" element={<PrivateRoute Component={Main} />} />
                 <Route path="/login" element={<Login />} />
+                <Route path="/sso/simple" element={<SimpleSSOPassthrough />} />
+
                 <Route
                   path="/workspace/:slug/settings/:tab"
                   element={<ManagerRoute Component={WorkspaceSettings} />}
diff --git a/frontend/src/models/system.js b/frontend/src/models/system.js
index 1039d6de25c0e25dc9b2755699c95884f1f1ba1c..4231c83c810adaf24349aaeb98698b5335d73135 100644
--- a/frontend/src/models/system.js
+++ b/frontend/src/models/system.js
@@ -706,6 +706,30 @@ const System = {
     );
     return { viewable: isViewable, error: null };
   },
+
+  /**
+   * Validates a temporary auth token and logs in the user if the token is valid.
+   * @param {string} publicToken - the token to validate against
+   * @returns {Promise<{valid: boolean, user: import("@prisma/client").users | null, token: string | null, message: string | null}>}
+   */
+  simpleSSOLogin: async function (publicToken) {
+    return fetch(`${API_BASE}/request-token/sso/simple?token=${publicToken}`, {
+      method: "GET",
+    })
+      .then(async (res) => {
+        if (!res.ok) {
+          const text = await res.text();
+          if (!text.startsWith("{")) throw new Error(text);
+          return JSON.parse(text);
+        }
+        return await res.json();
+      })
+      .catch((e) => {
+        console.error(e);
+        return { valid: false, user: null, token: null, message: e.message };
+      });
+  },
+
   experimentalFeatures: {
     liveSync: LiveDocumentSync,
     agentPlugins: AgentPlugins,
diff --git a/frontend/src/pages/Login/SSO/simple.jsx b/frontend/src/pages/Login/SSO/simple.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..1ceedcfb8ec6ea36be0c000492221a46dead6e60
--- /dev/null
+++ b/frontend/src/pages/Login/SSO/simple.jsx
@@ -0,0 +1,54 @@
+import React, { useEffect, useState } from "react";
+import { FullScreenLoader } from "@/components/Preloader";
+import { Navigate } from "react-router-dom";
+import paths from "@/utils/paths";
+import useQuery from "@/hooks/useQuery";
+import System from "@/models/system";
+import { AUTH_TIMESTAMP, AUTH_TOKEN, AUTH_USER } from "@/utils/constants";
+
+export default function SimpleSSOPassthrough() {
+  const query = useQuery();
+  const redirectPath = query.get("redirectTo") || paths.home();
+  const [ready, setReady] = useState(false);
+  const [error, setError] = useState(null);
+
+  useEffect(() => {
+    try {
+      if (!query.get("token")) throw new Error("No token provided.");
+
+      // Clear any existing auth data
+      window.localStorage.removeItem(AUTH_USER);
+      window.localStorage.removeItem(AUTH_TOKEN);
+      window.localStorage.removeItem(AUTH_TIMESTAMP);
+
+      System.simpleSSOLogin(query.get("token"))
+        .then((res) => {
+          if (!res.valid) throw new Error(res.message);
+
+          window.localStorage.setItem(AUTH_USER, JSON.stringify(res.user));
+          window.localStorage.setItem(AUTH_TOKEN, res.token);
+          window.localStorage.setItem(AUTH_TIMESTAMP, Number(new Date()));
+          setReady(res.valid);
+        })
+        .catch((e) => {
+          setError(e.message);
+        });
+    } catch (e) {
+      setError(e.message);
+    }
+  }, []);
+
+  if (error)
+    return (
+      <div className="w-screen h-screen overflow-hidden bg-sidebar flex items-center justify-center flex-col gap-4">
+        <p className="text-white font-mono text-lg">{error}</p>
+        <p className="text-white/80 font-mono text-sm">
+          Please contact the system administrator about this error.
+        </p>
+      </div>
+    );
+  if (ready) return <Navigate to={redirectPath} />;
+
+  // Loading state by default
+  return <FullScreenLoader />;
+}
diff --git a/server/.env.example b/server/.env.example
index 9c513f62f87392cc80f1cf36939b8fa8e6bd7b81..1995892780666664e5e56868b22b3c693f97bb8e 100644
--- a/server/.env.example
+++ b/server/.env.example
@@ -280,4 +280,8 @@ TTS_PROVIDER="native"
 
 # Disable viewing chat history from the UI and frontend APIs.
 # See https://docs.anythingllm.com/configuration#disable-view-chat-history for more information.
-# DISABLE_VIEW_CHAT_HISTORY=1
\ No newline at end of file
+# DISABLE_VIEW_CHAT_HISTORY=1
+
+# Enable simple SSO passthrough to pre-authenticate users from a third party service.
+# See https://docs.anythingllm.com/configuration#simple-sso-passthrough for more information.
+# SIMPLE_SSO_ENABLED=1
diff --git a/server/endpoints/api/userManagement/index.js b/server/endpoints/api/userManagement/index.js
index 9b4e8c66f019e0a2e6c7a9d565388a11923335d9..733e1d3139aa366d4045b2ad64cb5f9002fa5432 100644
--- a/server/endpoints/api/userManagement/index.js
+++ b/server/endpoints/api/userManagement/index.js
@@ -1,5 +1,9 @@
 const { User } = require("../../../models/user");
+const { TemporaryAuthToken } = require("../../../models/temporaryAuthToken");
 const { multiUserMode } = require("../../../utils/http");
+const {
+  simpleSSOEnabled,
+} = require("../../../utils/middleware/simpleSSOEnabled");
 const { validApiKey } = require("../../../utils/middleware/validApiKey");
 
 function apiUserManagementEndpoints(app) {
@@ -59,6 +63,62 @@ function apiUserManagementEndpoints(app) {
       response.sendStatus(500).end();
     }
   });
+
+  app.get(
+    "/v1/users/:id/issue-auth-token",
+    [validApiKey, simpleSSOEnabled],
+    async (request, response) => {
+      /*
+      #swagger.tags = ['User Management']
+      #swagger.description = 'Issue a temporary auth token for a user'
+      #swagger.parameters['id'] = {
+        in: 'path',
+        description: 'The ID of the user to issue a temporary auth token for',
+        required: true,
+        type: 'string'
+      }
+      #swagger.responses[200] = {
+        content: {
+          "application/json": {
+            schema: {
+              type: 'object',
+              example: {
+                token: "1234567890",
+                loginPath: "/sso/simple?token=1234567890"
+              }
+            }
+          }
+        }
+      }
+    }
+    #swagger.responses[403] = {
+      schema: {
+        "$ref": "#/definitions/InvalidAPIKey"
+      }
+    }
+     #swagger.responses[401] = {
+      description: "Instance is not in Multi-User mode. Permission denied.",
+    }
+      */
+      try {
+        const { id: userId } = request.params;
+        const user = await User.get({ id: Number(userId) });
+        if (!user)
+          return response.status(404).json({ error: "User not found" });
+
+        const { token, error } = await TemporaryAuthToken.issue(userId);
+        if (error) return response.status(500).json({ error: error });
+
+        response.status(200).json({
+          token: String(token),
+          loginPath: `/sso/simple?token=${token}`,
+        });
+      } catch (e) {
+        console.error(e.message, e);
+        response.sendStatus(500).end();
+      }
+    }
+  );
 }
 
 module.exports = { apiUserManagementEndpoints };
diff --git a/server/endpoints/system.js b/server/endpoints/system.js
index 5e631b2f3f2647a9629f2c08ae08a71651a01701..6da117ff28b23bb8e28ac15ebccc1223d13ca00b 100644
--- a/server/endpoints/system.js
+++ b/server/endpoints/system.js
@@ -53,6 +53,8 @@ const { BrowserExtensionApiKey } = require("../models/browserExtensionApiKey");
 const {
   chatHistoryViewable,
 } = require("../utils/middleware/chatHistoryViewable");
+const { simpleSSOEnabled } = require("../utils/middleware/simpleSSOEnabled");
+const { TemporaryAuthToken } = require("../models/temporaryAuthToken");
 
 function systemEndpoints(app) {
   if (!app) return;
@@ -251,6 +253,49 @@ function systemEndpoints(app) {
     }
   });
 
+  app.get(
+    "/request-token/sso/simple",
+    [simpleSSOEnabled],
+    async (request, response) => {
+      const { token: tempAuthToken } = request.query;
+      const { sessionToken, token, error } =
+        await TemporaryAuthToken.validate(tempAuthToken);
+
+      if (error) {
+        await EventLogs.logEvent("failed_login_invalid_temporary_auth_token", {
+          ip: request.ip || "Unknown IP",
+          multiUserMode: true,
+        });
+        return response.status(401).json({
+          valid: false,
+          token: null,
+          message: `[001] An error occurred while validating the token: ${error}`,
+        });
+      }
+
+      await Telemetry.sendTelemetry(
+        "login_event",
+        { multiUserMode: true },
+        token.user.id
+      );
+      await EventLogs.logEvent(
+        "login_event",
+        {
+          ip: request.ip || "Unknown IP",
+          username: token.user.username || "Unknown user",
+        },
+        token.user.id
+      );
+
+      response.status(200).json({
+        valid: true,
+        user: User.filterFields(token.user),
+        token: sessionToken,
+        message: null,
+      });
+    }
+  );
+
   app.post(
     "/system/recover-account",
     [isMultiUserSetup],
diff --git a/server/models/temporaryAuthToken.js b/server/models/temporaryAuthToken.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f0c6b9f47e7041902333ede678d9433221db041
--- /dev/null
+++ b/server/models/temporaryAuthToken.js
@@ -0,0 +1,104 @@
+const { makeJWT } = require("../utils/http");
+const prisma = require("../utils/prisma");
+
+/**
+ * Temporary auth tokens are used for simple SSO.
+ * They simply enable the ability for a time-based token to be used in the query of the /sso/login URL
+ * to login as a user without the need of a username and password. These tokens are single-use and expire.
+ */
+const TemporaryAuthToken = {
+  expiry: 1000 * 60 * 6, // 1 hour
+  tablename: "temporary_auth_tokens",
+  writable: [],
+
+  makeTempToken: () => {
+    const uuidAPIKey = require("uuid-apikey");
+    return `allm-tat-${uuidAPIKey.create().apiKey}`;
+  },
+
+  /**
+   * Issues a temporary auth token for a user via its ID.
+   * @param {number} userId
+   * @returns {Promise<{token: string|null, error: string | null}>}
+   */
+  issue: async function (userId = null) {
+    if (!userId)
+      throw new Error("User ID is required to issue a temporary auth token.");
+    await this.invalidateUserTokens(userId);
+
+    try {
+      const token = this.makeTempToken();
+      const expiresAt = new Date(Date.now() + this.expiry);
+      await prisma.temporary_auth_tokens.create({
+        data: {
+          token,
+          expiresAt,
+          userId: Number(userId),
+        },
+      });
+
+      return { token, error: null };
+    } catch (error) {
+      console.error("FAILED TO CREATE TEMPORARY AUTH TOKEN.", error.message);
+      return { token: null, error: error.message };
+    }
+  },
+
+  /**
+   * Invalidates (deletes) all temporary auth tokens for a user via their ID.
+   * @param {number} userId
+   * @returns {Promise<boolean>}
+   */
+  invalidateUserTokens: async function (userId) {
+    if (!userId)
+      throw new Error(
+        "User ID is required to invalidate temporary auth tokens."
+      );
+    await prisma.temporary_auth_tokens.deleteMany({
+      where: { userId: Number(userId) },
+    });
+    return true;
+  },
+
+  /**
+   * Validates a temporary auth token and returns the session token
+   * to be set in the browser localStorage for authentication.
+   * @param {string} publicToken - the token to validate against
+   * @returns {Promise<{sessionToken: string|null, token: import("@prisma/client").temporary_auth_tokens & {user: import("@prisma/client").users} | null, error: string | null}>}
+   */
+  validate: async function (publicToken = "") {
+    /** @type {import("@prisma/client").temporary_auth_tokens & {user: import("@prisma/client").users} | undefined | null} **/
+    let token;
+
+    try {
+      if (!publicToken)
+        throw new Error(
+          "Public token is required to validate a temporary auth token."
+        );
+      token = await prisma.temporary_auth_tokens.findUnique({
+        where: { token: String(publicToken) },
+        include: { user: true },
+      });
+      if (!token) throw new Error("Invalid token.");
+      if (token.expiresAt < new Date()) throw new Error("Token expired.");
+      if (token.user.suspended) throw new Error("User account suspended.");
+
+      // Create a new session token for the user valid for 30 days
+      const sessionToken = makeJWT(
+        { id: token.user.id, username: token.user.username },
+        "30d"
+      );
+
+      return { sessionToken, token, error: null };
+    } catch (error) {
+      console.error("FAILED TO VALIDATE TEMPORARY AUTH TOKEN.", error.message);
+      return { sessionToken: null, token: null, error: error.message };
+    } finally {
+      // Delete the token after it has been used under all circumstances if it was retrieved
+      if (token)
+        await prisma.temporary_auth_tokens.delete({ where: { id: token.id } });
+    }
+  },
+};
+
+module.exports = { TemporaryAuthToken };
diff --git a/server/prisma/migrations/20241029203722_init/migration.sql b/server/prisma/migrations/20241029203722_init/migration.sql
new file mode 100644
index 0000000000000000000000000000000000000000..29ee89ad5a7212441daa22fa0006b9ffebf88f3a
--- /dev/null
+++ b/server/prisma/migrations/20241029203722_init/migration.sql
@@ -0,0 +1,12 @@
+-- CreateTable
+CREATE TABLE "temporary_auth_tokens" (
+    "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+    "token" TEXT NOT NULL,
+    "userId" INTEGER NOT NULL,
+    "expiresAt" DATETIME NOT NULL,
+    "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    CONSTRAINT "temporary_auth_tokens_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+-- CreateIndex
+CREATE UNIQUE INDEX "temporary_auth_tokens_token_key" ON "temporary_auth_tokens"("token");
diff --git a/server/prisma/schema.prisma b/server/prisma/schema.prisma
index b96130888530af1dde978fbb574d14f646bbeffc..143646e6579f69f4add5a0df9c03ecca33b1ab8f 100644
--- a/server/prisma/schema.prisma
+++ b/server/prisma/schema.prisma
@@ -78,6 +78,7 @@ model users {
   workspace_agent_invocations workspace_agent_invocations[]
   slash_command_presets       slash_command_presets[]
   browser_extension_api_keys  browser_extension_api_keys[]
+  temporary_auth_tokens       temporary_auth_tokens[]
 }
 
 model recovery_codes {
@@ -311,3 +312,15 @@ model browser_extension_api_keys {
 
   @@index([user_id])
 }
+
+model temporary_auth_tokens {
+  id        Int      @id @default(autoincrement())
+  token     String   @unique
+  userId    Int
+  expiresAt DateTime
+  createdAt DateTime @default(now())
+  user      users    @relation(fields: [userId], references: [id], onDelete: Cascade)
+
+  @@index([token])
+  @@index([userId])
+}
diff --git a/server/swagger/openapi.json b/server/swagger/openapi.json
index fb343ee836202f442b60357c76b3e3fa84d44498..1222b78b247e40b791c2d32bc9eca24afc4b8b31 100644
--- a/server/swagger/openapi.json
+++ b/server/swagger/openapi.json
@@ -2877,6 +2877,65 @@
         }
       }
     },
+    "/v1/users/{id}/issue-auth-token": {
+      "get": {
+        "tags": [
+          "User Management"
+        ],
+        "description": "Issue a temporary auth token for a user",
+        "parameters": [
+          {
+            "name": "id",
+            "in": "path",
+            "required": true,
+            "schema": {
+              "type": "string"
+            },
+            "description": "The ID of the user to issue a temporary auth token for"
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "OK",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "object",
+                  "example": {
+                    "token": "1234567890",
+                    "loginPath": "/sso/simple?token=1234567890"
+                  }
+                }
+              }
+            }
+          },
+          "401": {
+            "description": "Instance is not in Multi-User mode. Permission denied."
+          },
+          "403": {
+            "description": "Forbidden",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/InvalidAPIKey"
+                }
+              },
+              "application/xml": {
+                "schema": {
+                  "$ref": "#/components/schemas/InvalidAPIKey"
+                }
+              }
+            }
+          },
+          "404": {
+            "description": "Not Found"
+          },
+          "500": {
+            "description": "Internal Server Error"
+          }
+        }
+      }
+    },
     "/v1/openai/models": {
       "get": {
         "tags": [
diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js
index d705fb73066b9e8fc2e7161a1fef53885093b7cc..a884f1324ba3d1949de426d09bb99e984a95a2ae 100644
--- a/server/utils/helpers/updateENV.js
+++ b/server/utils/helpers/updateENV.js
@@ -899,6 +899,8 @@ function dumpENV() {
     "HTTPS_KEY_PATH",
     // Other Configuration Keys
     "DISABLE_VIEW_CHAT_HISTORY",
+    // Simple SSO
+    "SIMPLE_SSO_ENABLED",
   ];
 
   // Simple sanitization of each value to prevent ENV injection via newline or quote escaping.
diff --git a/server/utils/middleware/simpleSSOEnabled.js b/server/utils/middleware/simpleSSOEnabled.js
new file mode 100644
index 0000000000000000000000000000000000000000..903200c037868ae016010f60118c8b9880175e29
--- /dev/null
+++ b/server/utils/middleware/simpleSSOEnabled.js
@@ -0,0 +1,39 @@
+const { SystemSettings } = require("../../models/systemSettings");
+
+/**
+ * Checks if simple SSO is enabled for issuance of temporary auth tokens.
+ * Note: This middleware must be called after `validApiKey`.
+ * @param {import("express").Request} request
+ * @param {import("express").Response} response
+ * @param {import("express").NextFunction} next
+ * @returns {void}
+ */
+async function simpleSSOEnabled(_, response, next) {
+  if (!("SIMPLE_SSO_ENABLED" in process.env)) {
+    return response
+      .status(403)
+      .send(
+        "Simple SSO is not enabled. It must be enabled to validate or issue temporary auth tokens."
+      );
+  }
+
+  // If the multi-user mode response local is not set, we need to check if it's enabled.
+  if (!("multiUserMode" in response.locals)) {
+    const multiUserMode = await SystemSettings.isMultiUserMode();
+    response.locals.multiUserMode = multiUserMode;
+  }
+
+  if (!response.locals.multiUserMode) {
+    return response
+      .status(403)
+      .send(
+        "Multi-User mode is not enabled. It must be enabled to use Simple SSO."
+      );
+  }
+
+  next();
+}
+
+module.exports = {
+  simpleSSOEnabled,
+};