coyotte508 HF Staff commited on
Commit
248183e
·
unverified ·
1 Parent(s): c4f6eb3

Automatic login (#1900)

Browse files

* Automatic login

* update debug message with correct port

* fix passing forward token

.env CHANGED
@@ -10,6 +10,8 @@ OPENAI_BASE_URL=https://router.huggingface.co/v1
10
  OPENAI_API_KEY=#your provider API key (works for HF router, OpenAI, LM Studio, etc.).
11
  # When set to true, user token will be used for inference calls
12
  USE_USER_TOKEN=false
 
 
13
 
14
  ### MongoDB ###
15
  MONGODB_URL=#your mongodb URL here, use chat-ui-db image if you don't want to set this
 
10
  OPENAI_API_KEY=#your provider API key (works for HF router, OpenAI, LM Studio, etc.).
11
  # When set to true, user token will be used for inference calls
12
  USE_USER_TOKEN=false
13
+ # Automatically redirect to oauth login page if user is not logged in, when set to "true"
14
+ AUTOMATIC_LOGIN=false
15
 
16
  ### MongoDB ###
17
  MONGODB_URL=#your mongodb URL here, use chat-ui-db image if you don't want to set this
src/hooks.server.ts CHANGED
@@ -2,7 +2,12 @@ import { config, ready } from "$lib/server/config";
2
  import type { Handle, HandleServerError, ServerInit, HandleFetch } from "@sveltejs/kit";
3
  import { collections } from "$lib/server/database";
4
  import { base } from "$app/paths";
5
- import { authenticateRequest, refreshSessionCookie, requiresUser } from "$lib/server/auth";
 
 
 
 
 
6
  import { ERROR_MESSAGES } from "$lib/stores/errors";
7
  import { addWeeks } from "date-fns";
8
  import { checkAndRunMigrations } from "$lib/migrations/migrations";
@@ -126,8 +131,17 @@ export const handle: Handle = async ({ event, resolve }) => {
126
  { type: "svelte", value: event.cookies }
127
  );
128
 
129
- event.locals.user = auth.user || undefined;
130
  event.locals.sessionId = auth.sessionId;
 
 
 
 
 
 
 
 
 
 
131
  event.locals.token = auth.token;
132
 
133
  event.locals.isAdmin =
 
2
  import type { Handle, HandleServerError, ServerInit, HandleFetch } from "@sveltejs/kit";
3
  import { collections } from "$lib/server/database";
4
  import { base } from "$app/paths";
5
+ import {
6
+ authenticateRequest,
7
+ refreshSessionCookie,
8
+ requiresUser,
9
+ triggerOauthFlow,
10
+ } from "$lib/server/auth";
11
  import { ERROR_MESSAGES } from "$lib/stores/errors";
12
  import { addWeeks } from "date-fns";
13
  import { checkAndRunMigrations } from "$lib/migrations/migrations";
 
131
  { type: "svelte", value: event.cookies }
132
  );
133
 
 
134
  event.locals.sessionId = auth.sessionId;
135
+
136
+ if (
137
+ !auth.user &&
138
+ config.AUTOMATIC_LOGIN === "true" &&
139
+ !event.url.pathname.startsWith(`${base}/login`)
140
+ ) {
141
+ return await triggerOauthFlow({ request: event.request, url: event.url, locals: event.locals });
142
+ }
143
+
144
+ event.locals.user = auth.user || undefined;
145
  event.locals.token = auth.token;
146
 
147
  event.locals.isAdmin =
src/lib/server/adminToken.ts CHANGED
@@ -37,9 +37,11 @@ class AdminTokenManager {
37
  // if admin token is set, don't display it
38
  if (!this.enabled || config.ADMIN_TOKEN) return;
39
 
40
- let port = process.argv.includes("--port")
41
- ? parseInt(process.argv[process.argv.indexOf("--port") + 1])
42
- : undefined;
 
 
43
 
44
  if (!port) {
45
  const mode = process.argv.find((arg) => arg === "preview" || arg === "dev");
 
37
  // if admin token is set, don't display it
38
  if (!this.enabled || config.ADMIN_TOKEN) return;
39
 
40
+ let port = process.env.PORT
41
+ ? parseInt(process.env.PORT)
42
+ : process.argv.includes("--port")
43
+ ? parseInt(process.argv[process.argv.indexOf("--port") + 1])
44
+ : undefined;
45
 
46
  if (!port) {
47
  const mode = process.argv.find((arg) => arg === "preview" || arg === "dev");
src/lib/server/auth.ts CHANGED
@@ -10,7 +10,7 @@ import { config } from "$lib/server/config";
10
  import { sha256 } from "$lib/utils/sha256";
11
  import { z } from "zod";
12
  import { dev } from "$app/environment";
13
- import type { Cookies } from "@sveltejs/kit";
14
  import { collections } from "$lib/server/database";
15
  import JSON5 from "json5";
16
  import { logger } from "$lib/server/logger";
@@ -19,6 +19,7 @@ import type { Cookie } from "elysia";
19
  import { adminTokenManager } from "./adminToken";
20
  import type { User } from "$lib/types/User";
21
  import type { Session } from "$lib/types/Session";
 
22
 
23
  export interface OIDCSettings {
24
  redirectURI: string;
@@ -359,3 +360,32 @@ export async function authenticateRequest(
359
 
360
  return { user: undefined, sessionId, secretSessionId, isAdmin: false };
361
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  import { sha256 } from "$lib/utils/sha256";
11
  import { z } from "zod";
12
  import { dev } from "$app/environment";
13
+ import { redirect, type Cookies } from "@sveltejs/kit";
14
  import { collections } from "$lib/server/database";
15
  import JSON5 from "json5";
16
  import { logger } from "$lib/server/logger";
 
19
  import { adminTokenManager } from "./adminToken";
20
  import type { User } from "$lib/types/User";
21
  import type { Session } from "$lib/types/Session";
22
+ import { base } from "$app/paths";
23
 
24
  export interface OIDCSettings {
25
  redirectURI: string;
 
360
 
361
  return { user: undefined, sessionId, secretSessionId, isAdmin: false };
362
  }
363
+
364
+ export async function triggerOauthFlow({
365
+ request,
366
+ url,
367
+ locals,
368
+ }: {
369
+ request: Request;
370
+ url: URL;
371
+ locals: App.Locals;
372
+ }): Promise<Response> {
373
+ const referer = request.headers.get("referer");
374
+ let redirectURI = `${(referer ? new URL(referer) : url).origin}${base}/login/callback`;
375
+
376
+ // TODO: Handle errors if provider is not responding
377
+
378
+ if (url.searchParams.has("callback")) {
379
+ const callback = url.searchParams.get("callback") || redirectURI;
380
+ if (config.ALTERNATIVE_REDIRECT_URLS.includes(callback)) {
381
+ redirectURI = callback;
382
+ }
383
+ }
384
+
385
+ const authorizationUrl = await getOIDCAuthorizationUrl(
386
+ { redirectURI },
387
+ { sessionId: locals.sessionId }
388
+ );
389
+
390
+ throw redirect(302, authorizationUrl);
391
+ }
src/lib/server/endpoints/openai/endpointOai.ts CHANGED
@@ -106,7 +106,14 @@ export async function endpointOai(
106
  const imageProcessor = makeImageProcessor(multimodal.image);
107
 
108
  if (completion === "completions") {
109
- return async ({ messages, preprompt, continueMessage, generateSettings, conversationId }) => {
 
 
 
 
 
 
 
110
  const prompt = await buildPrompt({
111
  messages,
112
  continueMessage,
@@ -132,13 +139,21 @@ export async function endpointOai(
132
  headers: {
133
  "ChatUI-Conversation-ID": conversationId?.toString() ?? "",
134
  "X-use-cache": "false",
 
135
  },
136
  });
137
 
138
  return openAICompletionToTextGenerationStream(openAICompletion);
139
  };
140
  } else if (completion === "chat_completions") {
141
- return async ({ messages, preprompt, generateSettings, conversationId, isMultimodal }) => {
 
 
 
 
 
 
 
142
  // Format messages for the chat API, handling multimodal content if supported
143
  let messagesOpenAI: OpenAI.Chat.Completions.ChatCompletionMessageParam[] =
144
  await prepareMessages(messages, imageProcessor, isMultimodal ?? model.multimodal);
@@ -186,6 +201,7 @@ export async function endpointOai(
186
  headers: {
187
  "ChatUI-Conversation-ID": conversationId?.toString() ?? "",
188
  "X-use-cache": "false",
 
189
  },
190
  }
191
  );
@@ -198,6 +214,7 @@ export async function endpointOai(
198
  headers: {
199
  "ChatUI-Conversation-ID": conversationId?.toString() ?? "",
200
  "X-use-cache": "false",
 
201
  },
202
  }
203
  );
 
106
  const imageProcessor = makeImageProcessor(multimodal.image);
107
 
108
  if (completion === "completions") {
109
+ return async ({
110
+ messages,
111
+ preprompt,
112
+ continueMessage,
113
+ generateSettings,
114
+ conversationId,
115
+ locals,
116
+ }) => {
117
  const prompt = await buildPrompt({
118
  messages,
119
  continueMessage,
 
139
  headers: {
140
  "ChatUI-Conversation-ID": conversationId?.toString() ?? "",
141
  "X-use-cache": "false",
142
+ ...(locals?.token ? { Authorization: `Bearer ${locals.token}` } : {}),
143
  },
144
  });
145
 
146
  return openAICompletionToTextGenerationStream(openAICompletion);
147
  };
148
  } else if (completion === "chat_completions") {
149
+ return async ({
150
+ messages,
151
+ preprompt,
152
+ generateSettings,
153
+ conversationId,
154
+ isMultimodal,
155
+ locals,
156
+ }) => {
157
  // Format messages for the chat API, handling multimodal content if supported
158
  let messagesOpenAI: OpenAI.Chat.Completions.ChatCompletionMessageParam[] =
159
  await prepareMessages(messages, imageProcessor, isMultimodal ?? model.multimodal);
 
201
  headers: {
202
  "ChatUI-Conversation-ID": conversationId?.toString() ?? "",
203
  "X-use-cache": "false",
204
+ ...(locals?.token ? { Authorization: `Bearer ${locals.token}` } : {}),
205
  },
206
  }
207
  );
 
214
  headers: {
215
  "ChatUI-Conversation-ID": conversationId?.toString() ?? "",
216
  "X-use-cache": "false",
217
+ ...(locals?.token ? { Authorization: `Bearer ${locals.token}` } : {}),
218
  },
219
  }
220
  );
src/routes/login/+server.ts CHANGED
@@ -1,29 +1,5 @@
1
- import { getOIDCAuthorizationUrl } from "$lib/server/auth";
2
- import { base } from "$app/paths";
3
- import { config } from "$lib/server/config";
4
 
5
  export async function GET({ request, url, locals }) {
6
- const referer = request.headers.get("referer");
7
- let redirectURI = `${(referer ? new URL(referer) : url).origin}${base}/login/callback`;
8
-
9
- // TODO: Handle errors if provider is not responding
10
-
11
- if (url.searchParams.has("callback")) {
12
- const callback = url.searchParams.get("callback") || redirectURI;
13
- if (config.ALTERNATIVE_REDIRECT_URLS.includes(callback)) {
14
- redirectURI = callback;
15
- }
16
- }
17
-
18
- const authorizationUrl = await getOIDCAuthorizationUrl(
19
- { redirectURI },
20
- { sessionId: locals.sessionId }
21
- );
22
-
23
- return new Response(null, {
24
- status: 302,
25
- headers: {
26
- Location: authorizationUrl,
27
- },
28
- });
29
  }
 
1
+ import { triggerOauthFlow } from "$lib/server/auth";
 
 
2
 
3
  export async function GET({ request, url, locals }) {
4
+ return await triggerOauthFlow({ request, url, locals });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  }