Integrating LibreChat with Microsoft Azure Entra ID (formerly Azure AD) and SharePoint is technically demanding and requires precise configuration of multiple components. This guide documents the complete setup process, including all pitfalls and their solutions.
What we achieve:
- Single Sign-On (SSO) with Microsoft Entra ID
- SharePoint/OneDrive File Picker integration
- Azure Blob Storage for file uploads
- Entra ID People Search for sharing features
Prerequisites
- Azure Subscription with Entra ID (Azure AD)
- LibreChat v0.8.1 or higher
- SharePoint Online tenant
- Admin rights for Azure AD and SharePoint
Azure AD App Registration
Create New App Registration
- Navigate to Azure Portal > Entra ID > App registrations
- Click New registration
- Configure:
- Name:
LibreChat(or your preferred name) - Supported account types: “Accounts in this organizational directory only”
- Redirect URI:
https://your-domain.com/oauth/openid/callback
- Name:
Create Client Secret
- Go to Certificates & secrets
- Click New client secret
- Choose a validity period (recommended: 24 months)
- IMPORTANT: Copy the Secret Value immediately - it’s only shown once!
Note Important IDs
Record the following values from the Overview page:
- Application (client) ID:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - Directory (tenant) ID:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - Object ID:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx(for API calls)
API Exposition for On-Behalf-Of (OBO) Flow
CRITICAL: Without this configuration, SharePoint integration will NOT work!
The OBO flow allows LibreChat to exchange the user token for a Microsoft Graph token. For this, the app must expose an API.
Set Application ID URI
az ad app update \
--id <APPLICATION_CLIENT_ID> \
--identifier-uris "api://<APPLICATION_CLIENT_ID>"
Create OAuth2 Permission Scope
# Generate scope ID
SCOPE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
# Add API scope
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/applications/<OBJECT_ID>" \
--body '{
"api": {
"oauth2PermissionScopes": [
{
"adminConsentDescription": "Allow the application to access LibreChat on behalf of the signed-in user.",
"adminConsentDisplayName": "Access LibreChat",
"id": "'$SCOPE_ID'",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Allow the application to access LibreChat on your behalf.",
"userConsentDisplayName": "Access LibreChat",
"value": "default"
}
]
}
}'
Add App as Pre-Authorized Client
The app must authorize itself as a trusted client for the OBO flow:
# Get scope ID
SCOPE_ID=$(az ad app show --id <APPLICATION_CLIENT_ID> \
--query "api.oauth2PermissionScopes[0].id" -o tsv)
# Add pre-authorization
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/applications/<OBJECT_ID>" \
--body '{
"api": {
"preAuthorizedApplications": [
{
"appId": "<APPLICATION_CLIENT_ID>",
"delegatedPermissionIds": ["'$SCOPE_ID'"]
}
]
}
}'
Token Configuration
IMPORTANT: Without the email claim in the token, existing users cannot authenticate!
LibreChat requires the email claim in the ID token to correctly identify users. By default, Entra ID does not include this claim.
Add Optional Claims
az rest --method PATCH \
--uri "https://graph.microsoft.com/v1.0/applications/<OBJECT_ID>" \
--body '{
"optionalClaims": {
"idToken": [
{
"name": "email",
"source": null,
"essential": true,
"additionalProperties": []
},
{
"name": "upn",
"source": null,
"essential": false,
"additionalProperties": []
}
],
"accessToken": [
{
"name": "email",
"source": null,
"essential": true,
"additionalProperties": []
}
]
}
}'
Verification
az ad app show --id <APPLICATION_CLIENT_ID> --query "optionalClaims" -o json
Expected output:
{
"accessToken": [{"name": "email", "essential": true, ...}],
"idToken": [{"name": "email", "essential": true, ...}, {"name": "upn", ...}],
"saml2Token": []
}
Microsoft Graph API Permissions
Required Delegated Permissions
| Permission | Type | Description |
|---|---|---|
User.Read | Delegated | Read user profile |
Files.Read.All | Delegated | Read files (OneDrive/SharePoint) |
offline_access | Delegated | Obtain refresh tokens |
People.Read | Delegated | Search contacts/people |
User.ReadBasic.All | Delegated | Read basic user info |
GroupMember.Read.All | Delegated (Admin) | Read group memberships |
Add Permissions
In Azure Portal:
- API permissions > Add a permission
- Microsoft Graph > Delegated permissions
- Select the permissions listed above
- Click Grant admin consent
Or via CLI:
# Add User.Read
az ad app permission add \
--id <APPLICATION_CLIENT_ID> \
--api 00000003-0000-0000-c000-000000000000 \
--api-permissions e1fe6dd8-ba31-4d61-89e7-88639da4683d=Scope
# Grant admin consent
az ad app permission admin-consent --id <APPLICATION_CLIENT_ID>
SharePoint API Permissions
Add SharePoint Permission
| Permission | Type | Description |
|---|---|---|
AllSites.Read | Delegated | Read all SharePoint sites |
# SharePoint API ID: 00000003-0000-0ff1-ce00-000000000000
az ad app permission add \
--id <APPLICATION_CLIENT_ID> \
--api 00000003-0000-0ff1-ce00-000000000000 \
--api-permissions 4e0d77b0-96ba-4398-af14-3baa780278f4=Scope
Admin Consent
SharePoint permissions require admin consent:
az ad app permission admin-consent --id <APPLICATION_CLIENT_ID>
LibreChat Environment Variables
OIDC Configuration
# OIDC base configuration
OPENID_ISSUER=https://login.microsoftonline.com/<TENANT_ID>/v2.0
OPENID_CLIENT_ID=<APPLICATION_CLIENT_ID>
OPENID_CLIENT_SECRET=<CLIENT_SECRET>
OPENID_CALLBACK_URL=/oauth/openid/callback
OPENID_BUTTON_LABEL=Microsoft Login
# CRITICAL: API scope MUST be included for OBO flow!
OPENID_SCOPE=api://<APPLICATION_CLIENT_ID>/default openid profile email offline_access
# Token reuse for SharePoint - MUST be enabled!
OPENID_REUSE_TOKENS=true
# Enable social login
ALLOW_SOCIAL_LOGIN=true
SharePoint Integration
# Enable SharePoint file picker
ENABLE_SHAREPOINT_FILEPICKER=true
SHAREPOINT_BASE_URL=https://<TENANT>.sharepoint.com
SHAREPOINT_PICKER_SHAREPOINT_SCOPE=https://<TENANT>.sharepoint.com/AllSites.Read
SHAREPOINT_PICKER_GRAPH_SCOPE=Files.Read.All
Entra ID People Search (Optional)
# Entra ID integration for people search in sharing system
USE_ENTRA_ID_FOR_PEOPLE_SEARCH=true
ENTRA_ID_INCLUDE_OWNERS_AS_MEMBERS=true
Azure Blob Storage (Optional)
# For Managed Identity (recommended):
AZURE_STORAGE_ACCOUNT_NAME=<STORAGE_ACCOUNT_NAME>
AZURE_STORAGE_PUBLIC_ACCESS=false
AZURE_CONTAINER_NAME=files
# OR for Connection String:
# AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=https;AccountName=...
In librechat.yaml:
version: 1.3.1
cache: true
fileStrategy: "azure_blob"
Common Problems and Solutions
Problem 1: 401 Unauthorized Loop After Login
Symptoms:
- Login with Entra ID succeeds
- Immediately followed by 401 errors on all API endpoints
- Browser shows endless token refresh attempts
Cause:
OPENID_REUSE_TOKENS=true is enabled, but:
- API is not exposed (missing
api://scope) - OR email claim is missing from token
- OR app is not pre-authorized
Solution:
- Check API exposition (see section above)
- Check token configuration
- Check pre-authorization
- OIDC_SCOPE must contain the API scope:
api://<CLIENT_ID>/default
Problem 2: SharePoint Picker is Empty
Symptoms:
- Login works
- SharePoint picker opens
- No files/sites are displayed
Cause:
- Guest account without SharePoint access
- Missing SharePoint API permissions
- OBO token exchange fails
Solution:
- Test with an internal account (not guest)
- Check SharePoint permissions and grant admin consent
- Check backend logs for
[exchangeTokenForGraphAccess] Token exchange failed
Problem 3: Token Exchange Failed
Backend log:
[exchangeTokenForGraphAccess] Token exchange failed: server responded with an error
Cause: The OBO flow is not correctly configured.
Solution:
- Add API scope to OIDC_SCOPE:
api://<CLIENT_ID>/default - Add app as pre-authorized client
- Restart the app service
Problem 4: Existing Users Cannot Sign In
Symptoms:
- New users can sign in
- Old users (before OIDC activation) receive 401 errors
Cause:
LibreChat bug (#9303): openIdJwtStrategy only searches for openidId, not email.
Solution:
- Add email claim as “essential” to the token
- OR: Manually set
openidIdin MongoDB for the user
Problem 5: Profile Picture Not Loading
Backend log:
[openidStrategy] downloadImage: Error downloading image at URL "https://graph.microsoft.com/v1.0/me/photo/$value": Error: Not Found (HTTP 404)
Cause: The user has no profile picture set in Entra ID.
Solution: This is not a critical error - LibreChat works without a profile picture.
Terraform Reference
App Service Configuration
resource "azurerm_linux_web_app" "librechat" {
name = "app-librechat"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
service_plan_id = azurerm_service_plan.main.id
site_config {
always_on = true
application_stack {
docker_image_name = "danny-avila/librechat:v0.8.1"
docker_registry_url = "https://ghcr.io"
}
}
app_settings = {
# OIDC Configuration
OPENID_ISSUER = var.oidc_issuer_url
OPENID_CLIENT_ID = var.oidc_client_id
OPENID_CLIENT_SECRET = var.oidc_client_secret
OPENID_CALLBACK_URL = "/oauth/openid/callback"
OPENID_SCOPE = "api://${var.oidc_client_id}/default openid profile email offline_access"
OPENID_BUTTON_LABEL = "Microsoft Login"
ALLOW_SOCIAL_LOGIN = "true"
# SharePoint Integration
ENABLE_SHAREPOINT_FILEPICKER = "true"
SHAREPOINT_BASE_URL = "https://${var.sharepoint_tenant}.sharepoint.com"
SHAREPOINT_PICKER_SHAREPOINT_SCOPE = "https://${var.sharepoint_tenant}.sharepoint.com/AllSites.Read"
SHAREPOINT_PICKER_GRAPH_SCOPE = "Files.Read.All"
OPENID_REUSE_TOKENS = "true"
# Entra ID People Search
USE_ENTRA_ID_FOR_PEOPLE_SEARCH = "true"
ENTRA_ID_INCLUDE_OWNERS_AS_MEMBERS = "true"
# Azure Blob Storage
AZURE_STORAGE_ACCOUNT_NAME = azurerm_storage_account.main.name
AZURE_STORAGE_PUBLIC_ACCESS = "false"
AZURE_CONTAINER_NAME = "files"
}
identity {
type = "SystemAssigned"
}
}
# Storage Blob Data Contributor for Managed Identity
resource "azurerm_role_assignment" "librechat_blob" {
scope = azurerm_storage_account.main.id
role_definition_name = "Storage Blob Data Contributor"
principal_id = azurerm_linux_web_app.librechat.identity[0].principal_id
}
Integration Checklist
- App Registration created
- Client Secret generated and securely stored
- API exposed with
api://<CLIENT_ID>URI - OAuth2 scope
defaultcreated - App added as pre-authorized client
- Email claim set as essential in token configuration
- Microsoft Graph permissions added (User.Read, Files.Read.All, etc.)
- SharePoint permission (AllSites.Read) added
- Admin consent granted for all permissions
- OIDC_SCOPE contains API scope:
api://<CLIENT_ID>/default -
OPENID_REUSE_TOKENS=trueconfigured - SharePoint environment variables set
Critical Points Summary
- The API scope in OIDC_SCOPE is MANDATORY for the OBO flow
- OPENID_REUSE_TOKENS=true is MANDATORY for SharePoint
- Email claim must be essential for existing users
- Pre-authorization is MANDATORY for token exchange
- Admin consent is MANDATORY for SharePoint permissions
Debugging Tips
- Check backend logs:
az webapp log tail --name <APP_NAME> --resource-group <RG> - Search for:
[openidStrategy],[exchangeTokenForGraphAccess],login success - Browser DevTools: Network tab for 401 errors, Console for JavaScript errors
- Use incognito window: Cached tokens can cause issues
Known Limitations
SharePoint Does NOT Work for Guest Users
Guest users (external accounts) can sign in, but the SharePoint file picker remains empty.
Technical cause: LibreChat uses the On-Behalf-Of (OBO) flow for SharePoint. This flow has a fundamental limitation:
- Guest signs in -> Token is issued in the home tenant (e.g., partner.com)
- LibreChat attempts token exchange in the resource tenant (your organization)
- Exchange fails because OBO is not designed for cross-tenant scenarios
OBO Flow with Guest Users:
┌──────────────┐ Token (Home Tenant) ┌───────────┐
│ Guest User │ ──────────────────────────> │ LibreChat │
│ @partner.com │ │ │
└──────────────┘ └─────┬─────┘
│
│ Token Exchange
│ (OBO Flow)
▼
┌───────────────┐
│ Microsoft │
│ Graph API │
│ (Your Tenant) │
└───────────────┘
│
▼
❌ ERROR
"Token from wrong tenant"
Workarounds:
| Option | Effort | Description |
|---|---|---|
| Use internal accounts | Low | Guests get accounts in your tenant |
| LibreChat fork | Very High | Modify code to use PKCE flow |
| Feature request | Low | Request from LibreChat maintainers |
| Disable SharePoint for guests | Low | Guests can only upload local files |
Summary:
| User Type | Login | Chat | SharePoint Picker |
|---|---|---|---|
| Internal (@yourdomain.com) | Yes | Yes | Yes |
| Guest (@external.yourdomain.com) | Yes | Yes | No |
| Guest (@partner.com) | Yes | Yes | No |
Cosmos DB: $bitsAllSet Not Supported
Problem:
[PermissionService.findAccessibleResources] Error: $bitsAllSet not supported
Cause: LibreChat uses MongoDB operators for permission checks that Azure Cosmos DB (MongoDB API) does not fully support.
Impact: The sharing/permissions system may not work correctly.
Workaround:
- Use real MongoDB (Atlas or self-hosted) instead of Cosmos DB
- Or: Don’t use sharing features
References
- LibreChat Documentation
- LibreChat SharePoint Integration
- LibreChat Token Reuse
- GitHub Issue #9303: OPENID_REUSE_TOKENS Bug
- GitHub Discussion #10907: SharePoint OBO Flow
- Microsoft OBO Flow Documentation
Need Help with Your LibreChat Implementation?
Setting up LibreChat with Azure Entra ID and SharePoint integration can be complex and time-consuming. If you need professional support for your enterprise AI chat deployment, alfatier GmbH offers comprehensive implementation services:
- Architecture design for secure, scalable LibreChat deployments
- Azure infrastructure setup with Terraform and best practices
- Entra ID integration including SSO, MFA, and conditional access
- SharePoint and Microsoft 365 integration
- Ongoing support and maintenance
Get in touch:
Kim Nis Neuhauss CEO & Founder, alfatier GmbH
- Email: [email protected]
- Web: alfatier.io
- Phone: +49 40 80 80 59 52
- LinkedIn: linkedin.com/company/alfatier
Bernstorffstraße 95, 22767 Hamburg, Germany