Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ SHAREPOINT_PICKER_GRAPH_SCOPE=Files.Read.All
### Usage

When properly configured:
1. Users will see "From SharePoint" option in the file attachment menu
1. Users will see a **From SharePoint** option in the **Attach** section of the [composer's **+** palette](/docs/features/composer#add-files)
2. Clicking it opens the native SharePoint file picker
3. Users can browse and select files from any SharePoint site or OneDrive they have access to
4. Selected files are downloaded and attached to the conversation
Expand Down
46 changes: 46 additions & 0 deletions content/docs/configuration/authentication/email.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,52 @@ EMAIL_FROM_NAME=LibreChat
ALLOW_PASSWORD_RESET=true
```

## Email Address Change

<Callout type="info" title="Availability">
Newer than **v0.8.8**. Available now on LibreChat's `dev` and `canary` branches, and in the next release.
</Callout>

Users with a local (email and password) account can change their registered email address themselves from **Settings > Account**. The feature is on by default and needs working email delivery (Mailgun or SMTP, configured above): without it, the option is hidden.

### User flow

1. In **Settings > Account**, next to **Email address**, the user selects **Change**.
2. In the **Change email address** dialog, they enter the **New email address** and their **Current password**, then select **Send verification link**.
3. LibreChat first sends a security notice ("Email change requested") to the current address, with the requested address and the request IP. It sends this before checking the password, so the account owner hears about every attempt, including rejected ones. If the request passes the checks below, a verification link goes to the new address.
4. The address changes only when the link is opened. Both the old and new addresses then receive a "Your email address was changed" notice, and the new address is marked as verified.

The request is rejected when the password is wrong, the new address equals the current one, the new address already belongs to another account, or its domain is not in [`registration.allowedDomains`](/docs/configuration/librechat_yaml/object_structure/registration#alloweddomains). Accounts that sign in through OAuth, OpenID Connect, SAML, or LDAP cannot use this flow.

The verification link is single-use and expires after `tokenTTLSeconds` (15 minutes by default). It also stops working if the password or email of the account changes before it is opened. Completing a change invalidates any password reset links issued for the previous address.

### Configuration

<OptionTable
options={[
[
'ALLOW_EMAIL_CHANGE',
'boolean',
'Allow local-account users to change their email address. Enabled when omitted. Overridden by emailChange.enabled in librechat.yaml.',
'# ALLOW_EMAIL_CHANGE=true',
],
]}
/>

In `librechat.yaml`, the `emailChange` block takes precedence over `ALLOW_EMAIL_CHANGE` and also sets the link lifetime:

```yaml filename="librechat.yaml"
emailChange:
enabled: true
tokenTTLSeconds: 900 # 60 to 86400, default 900 (15 minutes)
```

Each field falls back independently: `enabled` to `ALLOW_EMAIL_CHANGE` and then `true`; `tokenTTLSeconds` to `900`. Rate limits for requesting a change and for opening links are set under [`rateLimits.emailChange` and `rateLimits.emailChangeConfirm`](/docs/configuration/librechat_yaml/object_structure/config#ratelimits), or with the matching [environment variables](/docs/configuration/dotenv#email-change-rate-limiting).

<Callout type="warning" title="Multi-node rollouts">
Set `ALLOW_EMAIL_CHANGE=false` (or `emailChange.enabled: false`) until every node runs a version that includes this feature. Older nodes issue and accept password reset links that are not bound to an address, so a link held by the previous owner of an address could outlive the change and reset the renamed account.
</Callout>

## Troubleshooting

### Mailgun Issues
Expand Down
62 changes: 62 additions & 0 deletions content/docs/configuration/authentication/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,68 @@ Quick Tips:
alt="User registration screen"
/>

Related sign-in options for local accounts:

- [Passkeys](/docs/configuration/authentication/passkeys): passwordless sign-in with a device screen lock or security key (`ALLOW_PASSKEY_LOGIN`).
- [Email address change](/docs/configuration/authentication/email#email-address-change): lets users change their registered email from **Settings > Account** (`ALLOW_EMAIL_CHANGE`, on by default).

## Required Two-Factor Authentication

<Callout type="info" title="Availability">
Newer than **v0.8.8**. Available now on LibreChat's `dev` and `canary` branches, and in the next release.
</Callout>

Users can always turn on two-factor authentication (TOTP) themselves from **Settings > Account**. To make it mandatory, set:

```bash filename=".env"
ENFORCE_TWO_FACTOR_AUTHENTICATION=true
```

**Who it applies to:** local (email and password) and LDAP accounts. Accounts that sign in through OAuth, OpenID Connect, or SAML are not affected, because their identity provider is responsible for MFA. A federated account that tries to sign in with a password while enforcement is on is told to use its identity provider instead.

**What users see:** a user without 2FA who signs in (with a password, LDAP credentials, or a passkey) gets no session until setup is complete. They land on a **Two-Factor Authentication Required** screen ("Your administrator requires two-factor authentication. Set it up before continuing."), scan a QR code with an authenticator app, enter a code to verify, and save their backup codes. Users who are already signed in are moved into the same setup the next time their session is checked or refreshed, and access tokens issued before enrollment stop working. The setup session lasts 10 minutes; if it expires, the user returns to the login page and starts again.

**After enrollment:** the **Disable 2FA** control in **Settings > Account** shows **Required by administrator**, and the server rejects attempts to disable 2FA while the policy is on. Users can still regenerate backup codes.

<OptionTable
options={[
[
'ENFORCE_TWO_FACTOR_AUTHENTICATION',
'boolean',
'Require local and LDAP accounts to enroll in 2FA before a full session is issued. Default: false.',
'ENFORCE_TWO_FACTOR_AUTHENTICATION=false',
],
[
'TWO_FACTOR_TEMP_MAX',
'integer',
'Two-factor code attempts (sign-in challenge and enrollment confirmation) per TWO_FACTOR_TEMP_WINDOW. Defaults to LOGIN_MAX (7).',
'# TWO_FACTOR_TEMP_MAX=7',
],
[
'TWO_FACTOR_TEMP_WINDOW',
'integer',
'Window in minutes for TWO_FACTOR_TEMP_MAX. Defaults to LOGIN_WINDOW (5).',
'# TWO_FACTOR_TEMP_WINDOW=5',
],
[
'TWO_FACTOR_SETUP_MAX',
'integer',
'Enrollment steps that check no guessable code (starting setup, acknowledging backup codes, finishing). Kept separate so wrong codes cannot strand an enrollment. Default: 20.',
'# TWO_FACTOR_SETUP_MAX=20',
],
[
'TWO_FACTOR_SETUP_WINDOW',
'integer',
'Window in minutes for TWO_FACTOR_SETUP_MAX. Defaults to TWO_FACTOR_TEMP_WINDOW.',
'# TWO_FACTOR_SETUP_WINDOW=5',
],
]}
/>

<Callout type="info" title="Environment only">
`ENFORCE_TWO_FACTOR_AUTHENTICATION` and the `TWO_FACTOR_TEMP_*` and `TWO_FACTOR_SETUP_*` limits are process-wide `.env` settings. They apply before a request or tenant configuration is available, so they cannot be set in `librechat.yaml` or per tenant. Set the same values on every replica. The separate budget for managing 2FA from settings is [`rateLimits.twoFactorManagement`](/docs/configuration/librechat_yaml/object_structure/config#ratelimits).
</Callout>

## Session Expiry and Refresh Token

- Default values: session expiry: 15 minutes, refresh token expiry: 7 days
Expand Down
2 changes: 1 addition & 1 deletion content/docs/configuration/authentication/meta.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"title": "Authentication",
"icon": "Lock",
"pages": ["email", "ldap", "OAuth2-OIDC", "SAML"]
"pages": ["email", "passkeys", "ldap", "OAuth2-OIDC", "SAML"]
}
142 changes: 142 additions & 0 deletions content/docs/configuration/authentication/passkeys.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
---
title: Passkeys
icon: KeyRound
description: Let users sign in without a password using a device screen lock or a security key (WebAuthn). Covers enabling passkeys, the relying party settings, enrollment limits, and how passkeys interact with two-factor authentication.
---

Passkeys let users with a local (email and password) account sign in with their device screen lock, a password manager, or a hardware security key instead of typing a password. LibreChat implements them with WebAuthn. They are off by default.

<Callout type="info" title="Availability">
Newer than **v0.8.8**. Available now on LibreChat's `dev` and `canary` branches, and in the next release.
</Callout>

Use passkeys when you want a phishing-resistant, passwordless sign-in for local accounts. Accounts that sign in through OAuth, OpenID Connect, SAML, or LDAP keep using their provider and cannot add passkeys.

## Enable passkeys

<Steps>
<Step>

**Serve LibreChat over HTTPS.** Browsers only allow WebAuthn in a secure context. `http://localhost` is exempt, so local testing works without TLS.

</Step>
<Step>

**Turn the feature on in `.env`.** For a standard deployment, this is the only required setting. The relying party ID and allowed origins are derived from `DOMAIN_CLIENT` and `DOMAIN_SERVER`.

```bash filename=".env"
ALLOW_PASSKEY_LOGIN=true
```

</Step>
<Step>

**Pin the relying party ID (recommended).** Each passkey is permanently bound to the RP ID it was created under. If `DOMAIN_CLIENT` might ever change, set `PASSKEY_RP_ID` now so existing passkeys keep working.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Qualify when pinning the passkey RP ID preserves credentials

For deployments that later move to an unrelated hostname, pinning PASSKEY_RP_ID=chat.example.com does not keep existing passkeys working: WebAuthn requires the new origin's host to equal or be a subdomain of the pinned RP ID, so a move to a sibling such as new.example.com or another domain makes ceremonies fail. Limit this recommendation to host changes within the RP ID's scope and explain that a stable parent domain must be chosen before enrollment when sibling-subdomain moves are expected.

Useful? React with 馃憤聽/ 馃憥.


```bash filename=".env"
PASSKEY_RP_ID=chat.example.com
```

</Step>
<Step>

**Restart LibreChat.** The login page shows **Sign in with a passkey**, and **Settings > Account** shows a **Passkeys** section.

</Step>
</Steps>

## Configuration reference

<OptionTable
options={[
[
'ALLOW_PASSKEY_LOGIN',
'boolean',
'Enables passkey sign-in and the Passkeys section in account settings. Default: false.',
'ALLOW_PASSKEY_LOGIN=true',
],
[
'PASSKEY_RP_ID',
'string',
'Relying party ID: the domain passkeys are bound to. Must be a domain name (not an IP address) equal to, or a parent domain of, the host users visit. Defaults to the hostname of DOMAIN_CLIENT, or localhost.',
'# PASSKEY_RP_ID=chat.example.com',
],
[
'PASSKEY_RP_NAME',
'string',
'Name the authenticator shows when creating or using a passkey. Defaults to APP_TITLE, then LibreChat.',
'# PASSKEY_RP_NAME=LibreChat',
],
[
'PASSKEY_ORIGINS',
'string',
'Comma-separated list of origins allowed to run passkey ceremonies. Defaults to DOMAIN_CLIENT and DOMAIN_SERVER.',
'# PASSKEY_ORIGINS=https://chat.example.com',
],
[
'MAX_PASSKEYS_PER_USER',
'integer',
'Passkeys each account may enroll, from 1 to 100. Overridden by passkeys.perUserMax in librechat.yaml. Default: 20.',
'# MAX_PASSKEYS_PER_USER=20',
],
[
'PASSKEY_STEPUP_MAX',
'integer',
'Password-confirmed passkey add or remove attempts allowed per user in PASSKEY_STEPUP_WINDOW. Default: 20.',
'PASSKEY_STEPUP_MAX=20',
],
[
'PASSKEY_STEPUP_WINDOW',
'integer',
'Window in minutes for PASSKEY_STEPUP_MAX. Default: 15.',
'PASSKEY_STEPUP_WINDOW=15',
],
[
'PASSKEY_MAX',
'integer',
'Passkey sign-in requests allowed per IP in PASSKEY_WINDOW. One sign-in uses two requests. Requests over the limit get HTTP 429; they are not scored as violations because no user is signed in yet. Default: 20.',
'# PASSKEY_MAX=20',
],
[
'PASSKEY_WINDOW',
'integer',
'Window in minutes for PASSKEY_MAX. Default: 5.',
'# PASSKEY_WINDOW=5',
],
]}
/>

### Per-user limit in `librechat.yaml`

You can also set the enrollment cap in `librechat.yaml`:

```yaml filename="librechat.yaml"
passkeys:
perUserMax: 10
```

The cap resolves in this order: `passkeys.perUserMax` in `librechat.yaml`, then `MAX_PASSKEYS_PER_USER`, then the default of `20`. Values outside `1` to `100` are ignored and the next source is used. When a user reaches the cap, **Settings > Account** shows "You have reached the maximum number of passkeys". See [`passkeys`](/docs/configuration/librechat_yaml/object_structure/config#passkeys) in the config reference.

## What users see

**Adding a passkey**

1. Open **Settings > Account**, find **Passkeys**, and select **Manage**.
2. Select **Add passkey**.
3. Enter the account password in the **Confirm your password** dialog. A passkey is a complete sign-in on its own, so LibreChat asks for the password before creating one.
4. Complete the browser or device prompt. The new passkey appears in the list with a default name such as **This device**, **Phone or tablet**, or **Security key**.

Each entry shows when it was added and last used, and a **Synced** badge when the authenticator reports that the passkey is backed up (for example, by a password manager). Users can rename a passkey, and removing one (**Remove passkey**) also asks for the account password.

**Signing in**

On the login page, users select **Sign in with a passkey** and approve the device prompt. If the account has two-factor authentication enabled, LibreChat still asks for the 2FA code afterward, exactly as it does after a password sign-in.

## Behavior and caveats

- **Local accounts only.** Passkey enrollment and sign-in are limited to local accounts. Accounts created through an identity provider or LDAP must keep authenticating through that provider.
- **Works with email login disabled.** The **Sign in with a passkey** button and its routes depend only on `ALLOW_PASSKEY_LOGIN`. With `ALLOW_EMAIL_LOGIN=false`, existing local users can still sign in with passkeys they enrolled earlier.
- **Two-factor authentication.** Passkey sign-in goes through the same 2FA gate as password sign-in. With [`ENFORCE_TWO_FACTOR_AUTHENTICATION=true`](/docs/configuration/authentication#required-two-factor-authentication), a user who has not enrolled in 2FA is sent to the setup flow after signing in with a passkey.
- **Changing the RP ID orphans passkeys.** Passkeys created under one RP ID never work under another. Changing `PASSKEY_RP_ID`, or changing `DOMAIN_CLIENT` while `PASSKEY_RP_ID` is unset, leaves every existing passkey unusable; users must sign in another way and enroll again.
- **Origins must match.** If users reach LibreChat on an origin not covered by `PASSKEY_ORIGINS` (or the derived defaults), the browser shows "Passkeys are not available on this domain". Add every public origin to `PASSKEY_ORIGINS` when you serve LibreChat on more than one.
- **Password reset removes passkeys.** A completed password reset signs the account out everywhere and deletes all of its passkeys, so a passkey enrolled before the reset can no longer be used to get in. Users enroll again afterward.
Loading
Loading