lijunle nsarrazin HF Staff commited on
Commit
f61126a
·
unverified ·
1 Parent(s): b70b72a

Enable auth using trusted header (#1128)

Browse files

* Declare jwt-decode as dependency.

* Show email from JWT and hide signout

* Use special value for JWT user ID.

* fix user creation, fix linting

* formatting

* Update implem to use header instead of cookie

* create user id based on email

---------

Co-authored-by: Nathan Sarrazin <[email protected]>

.env CHANGED
@@ -6,6 +6,8 @@ MONGODB_DB_NAME=chat-ui
6
  MONGODB_DIRECT_CONNECTION=false
7
 
8
  COOKIE_NAME=hf-chat
 
 
9
  HF_TOKEN=#hf_<token> from https://huggingface.co/settings/token
10
  HF_API_ROOT=https://api-inference.huggingface.co/models
11
 
 
6
  MONGODB_DIRECT_CONNECTION=false
7
 
8
  COOKIE_NAME=hf-chat
9
+ TRUSTED_EMAIL_HEADER= # only set this if you understand the implications
10
+
11
  HF_TOKEN=#hf_<token> from https://huggingface.co/settings/token
12
  HF_API_ROOT=https://api-inference.huggingface.co/models
13
 
README.md CHANGED
@@ -147,6 +147,19 @@ OPENID_CONFIG=`{
147
 
148
  These variables will enable the openID sign-in modal for users.
149
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  ### Theming
151
 
152
  You can use a few environment variables to customize the look and feel of chat-ui. These are by default:
@@ -172,7 +185,7 @@ You can enable the web search through an API by adding `YDC_API_KEY` ([docs.you.
172
 
173
  You can also simply enable the local google websearch by setting `USE_LOCAL_WEBSEARCH=true` in your `.env.local` or specify a SearXNG instance by adding the query URL to `SEARXNG_QUERY_URL`.
174
 
175
- You can enable Javascript when parsing webpages to improve compatibility with `WEBSEARCH_JAVASCRIPT=true` at the cost of increased CPU usage. You'll want at least 4 cores when enabling.
176
 
177
  ### Custom models
178
 
@@ -232,7 +245,7 @@ The following is the default `chatPromptTemplate`, although newlines and indenti
232
 
233
  #### Multi modal model
234
 
235
- We currently support [IDEFICS](https://huggingface.co/blog/idefics) (hosted on TGI), OpenAI and Claude 3 as multimodal models. You can enable it by setting `multimodal: true` in your `MODELS` configuration. For IDEFICS, you must have a [PRO HF Api token](https://huggingface.co/settings/tokens). For OpenAI, see the [OpenAI section](#OpenAI). For Anthropic, see the [Anthropic section](#Anthropic).
236
 
237
  ```env
238
  {
 
147
 
148
  These variables will enable the openID sign-in modal for users.
149
 
150
+ ### Trusted header authentication
151
+
152
+ You can set the env variable `TRUSTED_EMAIL_HEADER` to point to the header that contains the user's email address. This will allow you to authenticate users from the header. This setup is usually combined with a proxy that will be in front of chat-ui and will handle the auth and set the header.
153
+
154
+ > [!WARNING]
155
+ > Make sure to only allow requests to chat-ui through your proxy which handles authentication, otherwise users could authenticate as anyone by setting the header manually! Only set this up if you understand the implications and know how to do it correctly.
156
+
157
+ Here is a list of header names for common auth providers:
158
+
159
+ - Tailscale Serve: `Tailscale-User-Login`
160
+ - Cloudflare Access: `Cf-Access-Authenticated-User-Email`
161
+ - oauth2-proxy: `X-Forwarded-Email`
162
+
163
  ### Theming
164
 
165
  You can use a few environment variables to customize the look and feel of chat-ui. These are by default:
 
185
 
186
  You can also simply enable the local google websearch by setting `USE_LOCAL_WEBSEARCH=true` in your `.env.local` or specify a SearXNG instance by adding the query URL to `SEARXNG_QUERY_URL`.
187
 
188
+ You can enable javascript when parsing webpages to improve compatibility with `WEBSEARCH_JAVASCRIPT=true` at the cost of increased CPU usage. You'll want at least 4 cores when enabling.
189
 
190
  ### Custom models
191
 
 
245
 
246
  #### Multi modal model
247
 
248
+ We currently support [IDEFICS](https://huggingface.co/blog/idefics) (hosted on TGI), OpenAI and Claude 3 as multimodal models. You can enable it by setting `multimodal: true` in your `MODELS` configuration. For IDEFICS, you must have a [PRO HF Api token](https://huggingface.co/settings/tokens). For OpenAI, see the [OpenAI section](#OpenAI). For Anthropic, see the [Anthropic section](#anthropic).
249
 
250
  ```env
251
  {
src/app.d.ts CHANGED
@@ -10,7 +10,7 @@ declare global {
10
  // interface Error {}
11
  interface Locals {
12
  sessionId: string;
13
- user?: User;
14
  }
15
 
16
  interface Error {
 
10
  // interface Error {}
11
  interface Locals {
12
  sessionId: string;
13
+ user?: User & { logoutDisabled?: boolean };
14
  }
15
 
16
  interface Error {
src/hooks.server.ts CHANGED
@@ -13,6 +13,7 @@ import { refreshAssistantsCounts } from "$lib/assistantStats/refresh-assistants-
13
  import { logger } from "$lib/server/logger";
14
  import { AbortedGenerations } from "$lib/server/abortedGenerations";
15
  import { MetricsServer } from "$lib/server/metrics";
 
16
 
17
  // TODO: move this code on a started server hook, instead of using a "building" flag
18
  if (!building) {
@@ -96,10 +97,29 @@ export const handle: Handle = async ({ event, resolve }) => {
96
 
97
  const token = event.cookies.get(env.COOKIE_NAME);
98
 
 
 
 
 
 
99
  let secretSessionId: string;
100
  let sessionId: string;
101
 
102
- if (token) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  secretSessionId = token;
104
  sessionId = await sha256(token);
105
 
 
13
  import { logger } from "$lib/server/logger";
14
  import { AbortedGenerations } from "$lib/server/abortedGenerations";
15
  import { MetricsServer } from "$lib/server/metrics";
16
+ import { ObjectId } from "mongodb";
17
 
18
  // TODO: move this code on a started server hook, instead of using a "building" flag
19
  if (!building) {
 
97
 
98
  const token = event.cookies.get(env.COOKIE_NAME);
99
 
100
+ // if the trusted email header is set we use it to get the user email
101
+ const email = env.TRUSTED_EMAIL_HEADER
102
+ ? event.request.headers.get(env.TRUSTED_EMAIL_HEADER)
103
+ : null;
104
+
105
  let secretSessionId: string;
106
  let sessionId: string;
107
 
108
+ if (email) {
109
+ secretSessionId = sessionId = await sha256(email);
110
+
111
+ event.locals.user = {
112
+ // generate id based on email
113
+ _id: new ObjectId(sessionId.slice(0, 24)),
114
+ name: email,
115
+ email,
116
+ createdAt: new Date(),
117
+ updatedAt: new Date(),
118
+ hfUserId: email,
119
+ avatarUrl: "",
120
+ logoutDisabled: true,
121
+ };
122
+ } else if (token) {
123
  secretSessionId = token;
124
  sessionId = await sha256(token);
125
 
src/lib/components/NavMenu.svelte CHANGED
@@ -89,12 +89,14 @@
89
  class="flex h-9 flex-none shrink items-center gap-1.5 truncate pr-2 text-gray-500 dark:text-gray-400"
90
  >{user?.username || user?.email}</span
91
  >
92
- <button
93
- type="submit"
94
- class="ml-auto h-6 flex-none items-center gap-1.5 rounded-md border bg-white px-2 text-gray-700 shadow-sm group-hover:flex hover:shadow-none md:hidden dark:border-gray-600 dark:bg-gray-600 dark:text-gray-400 dark:hover:text-gray-300"
95
- >
96
- Sign Out
97
- </button>
 
 
98
  </form>
99
  {/if}
100
  {#if canLogin}
 
89
  class="flex h-9 flex-none shrink items-center gap-1.5 truncate pr-2 text-gray-500 dark:text-gray-400"
90
  >{user?.username || user?.email}</span
91
  >
92
+ {#if !user.logoutDisabled}
93
+ <button
94
+ type="submit"
95
+ class="ml-auto h-6 flex-none items-center gap-1.5 rounded-md border bg-white px-2 text-gray-700 shadow-sm group-hover:flex hover:shadow-none md:hidden dark:border-gray-600 dark:bg-gray-600 dark:text-gray-400 dark:hover:text-gray-300"
96
+ >
97
+ Sign Out
98
+ </button>
99
+ {/if}
100
  </form>
101
  {/if}
102
  {#if canLogin}
src/routes/+layout.server.ts CHANGED
@@ -192,6 +192,7 @@ export const load: LayoutServerLoad = async ({ locals, depends }) => {
192
  username: locals.user.username,
193
  avatarUrl: locals.user.avatarUrl,
194
  email: locals.user.email,
 
195
  },
196
  assistant,
197
  enableAssistants,
 
192
  username: locals.user.username,
193
  avatarUrl: locals.user.avatarUrl,
194
  email: locals.user.email,
195
+ logoutDisabled: locals.user.logoutDisabled,
196
  },
197
  assistant,
198
  enableAssistants,