# How Lobe Chat Handles User Authentication: Better-Auth, XOR Tokens, and Custom Headers

> Discover how Lobe Chat secures user authentication using Better-Auth, XOR tokens, and custom headers. Learn about stateless, provider-agnostic security.

- Repository: [LobeHub/lobe-chat](https://github.com/lobehub/lobe-chat)
- Tags: deep-dive
- Published: 2026-03-03

---

**Lobe Chat uses Better-Auth to manage sessions, XOR-obfuscates the user ID into a custom `X-lobe-chat-auth` header, and validates this token on the server using `getUserAuth` to maintain stateless, provider-agnostic authentication.**

Lobe Chat implements a **stateless authentication architecture** built on top of Better-Auth, a lightweight wrapper around Next-Auth. This system allows the lobehub/lobe-chat repository to support multiple OAuth providers while maintaining a consistent **Lobe Chat user authentication** flow across web, desktop, and serverless environments.

## Server-Side Session Retrieval with `getUserAuth`

The server identifies incoming requests through the `getUserAuth` function defined in [`packages/utils/src/server/auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/packages/utils/src/server/auth.ts). This utility extracts the `X-lobe-chat-auth` header, reconstructs the session via Better-Auth, and returns the authenticated user ID.

```typescript
export const getUserAuth = async () => {
  const currentHeaders = await headers();
  const requestHeaders = Object.fromEntries(currentHeaders.entries());

  const session = await auth.api.getSession({
    headers: requestHeaders,
  });

  const userId = session?.user?.id;

  return { betterAuth: session, userId };
};

```

This function serves as the **single source of truth** for user identity across all server-side routes in Lobe Chat.

## Client-Side Token Generation and XOR Obfuscation

On the client side, Lobe Chat generates authentication tokens through `createAuthTokenWithPayload` in [`src/services/_auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/services/_auth.ts). The system uses a simple XOR obfuscation algorithm to encode the user ID and provider credentials using a secret key defined in [`src/envs/auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/envs/auth.ts).

```typescript
const createAuthTokenWithPayload = (payload = {}) => {
  const userId = userProfileSelectors.userId(useUserStore.getState());
  return obfuscatePayloadWithXOR<ClientSecretPayload>({ userId, ...payload }, SECRET_XOR_KEY);
};

```

The `SECRET_XOR_KEY` constant is set to `'LobeHub · LobeHub'`, providing a lightweight obfuscation layer that prevents casual inspection of the token payload while maintaining stateless session management.

## Provider-Specific Payload Handling

When interacting with AI providers that require API keys, Lobe Chat injects provider-specific credentials into the authentication token via `createPayloadWithKeyVaults` in [`src/services/_auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/services/_auth.ts).

```typescript
export const createPayloadWithKeyVaults = (provider: string) => {
  const keyVaults = aiProviderSelectors.providerKeyVaults(provider)(useAiInfraStore.getState()) || {};
  const runtimeProvider = resolveRuntimeProvider(provider);

  return {
    ...getProviderAuthPayload(runtimeProvider, keyVaults as any),
    runtimeProvider,
  };
};

```

This function retrieves encrypted API keys from the client's key vault, resolves the runtime provider configuration, and packages them into the payload that gets XOR-obfuscated and sent to the server.

## Header Construction and API Integration

The `createHeaderWithAuth` function in [`src/services/_auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/services/_auth.ts) orchestrates the final header assembly, injecting the `X-lobe-chat-auth` header into every API request.

```typescript
export const createHeaderWithAuth = async (params?: AuthParams): Promise<HeadersInit> => {
  let payload = params?.payload || {};

  if (params?.provider) {
    payload = { ...payload, ...createPayloadWithKeyVaults(params?.provider) };
  }

  const token = createAuthTokenWithPayload(payload);

  return { ...params?.headers, [LOBE_CHAT_AUTH_HEADER]: token };
};

```

All client-side API calls use this function to ensure the user's identity and provider credentials accompany every request to the Lobe Chat backend.

## Environment-Driven Provider Configuration

Authentication providers and security constants are centralized in [`src/envs/auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/envs/auth.ts). This file defines the header names and validates all OAuth provider configurations using a Zod schema.

```typescript
export const LOBE_CHAT_AUTH_HEADER = 'X-lobe-chat-auth';
export const LOBE_CHAT_OIDC_AUTH_HEADER = 'Oidc-Auth';

```

The schema supports Google, GitHub, Auth0, and other SSO providers, reading configuration from environment variables with both server-side and public (`NEXT_PUBLIC_`) prefixes to enable universal authentication flows.

## Better-Auth Client Integration

The frontend interacts with the authentication system through the Better-Auth client wrapper in [`src/libs/better-auth/auth-client.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/libs/better-auth/auth-client.ts). This module exports sign-in utilities and session hooks used throughout the UI.

```typescript
export const {
  signIn,
  signOut,
  useSession,
} = createAuthClient({
  plugins: [
    adminClient(),
    inferAdditionalFields<typeof auth>(),
    genericOAuthClient(),
    magicLinkClient(),
  ],
});

```

This configuration enables **admin APIs**, **generic OAuth flows**, and **magic link** authentication, providing a unified interface for all user authentication interactions in Lobe Chat.

## Summary

Lobe Chat's authentication architecture combines Better-Auth's session management with custom XOR-obfuscated tokens to create a stateless, provider-agnostic security layer. Key implementation details include:

- **Server-side validation** through `getUserAuth` in [`packages/utils/src/server/auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/packages/utils/src/server/auth.ts), which reconstructs user sessions from the `X-lobe-chat-auth` header.
- **Client-side token generation** using XOR obfuscation with a secret key defined in [`src/envs/auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/envs/auth.ts), encoding user IDs and provider API credentials.
- **Universal header injection** via `createHeaderWithAuth` in [`src/services/_auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/services/_auth.ts), ensuring every API request carries authentication state.
- **Environment-driven configuration** supporting multiple OAuth providers (Google, GitHub, Auth0) through a centralized Zod schema in [`src/envs/auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/envs/auth.ts).

This design enables Lobe Chat to support complex multi-provider authentication while maintaining lightweight, stateless session management suitable for serverless deployments.

## Frequently Asked Questions

### What authentication providers does Lobe Chat support?

Lobe Chat supports multiple SSO and OAuth providers including Google, GitHub, Auth0, and generic OAuth2 providers. These are configured through environment variables defined in [`src/envs/auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/envs/auth.ts), which validates provider credentials using a comprehensive Zod schema. The system also supports passwordless authentication via magic links and traditional email-based authentication through the Better-Auth client configuration in [`src/libs/better-auth/auth-client.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/libs/better-auth/auth-client.ts).

### How does Lobe Chat secure authentication tokens in transit?

Rather than transmitting raw session data, Lobe Chat XOR-obfuscates the user ID and provider credentials using a secret key (`'LobeHub · LobeHub'`) defined in [`src/envs/auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/envs/auth.ts). This obfuscated payload is placed in the `X-lobe-chat-auth` header via the `createHeaderWithAuth` function in [`src/services/_auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/services/_auth.ts). While not encryption, this obfuscation prevents casual inspection of token contents while maintaining the stateless nature required for serverless session management.

### What is the purpose of the `getUserAuth` function?

The `getUserAuth` function in [`packages/utils/src/server/auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/packages/utils/src/server/auth.ts) serves as the single source of truth for user identity on the server side. It extracts the `X-lobe-chat-auth` header from incoming requests, reconstructs the session using Better-Auth's `auth.api.getSession`, and returns the user ID and full session object. Server routes call this function at the entry point to validate authentication state before processing protected resources.

### How does Lobe Chat handle provider-specific API keys?

When making requests to AI providers that require authentication, Lobe Chat injects provider-specific credentials into the authentication token through the `createPayloadWithKeyVaults` function in [`src/services/_auth.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/services/_auth.ts). This function retrieves encrypted API keys from the client's key vault state, resolves the runtime provider configuration, and packages them into the payload that gets XOR-obfuscated. This allows the server to verify both user identity and provider access permissions in a single stateless request.