Conversation
jeswr
left a comment
There was a problem hiding this comment.
Partial review - to be completed tomorrow morning.
|
@PreciousOritsedere the primary architectural comments I have as I am completing this review are are:
|
I have pushed this commit to address this : "Theres still appears to be lots code specifying the content of the JSON document written to a Solid Pod. Since this document content is shared with the documents sent to MongoDB; please try and remove this custom code." |
Co-authored-by: Jesse Wright <63333554+jeswr@users.noreply.github.com>
…ng data on updates - Added req.user?.openidId check in saveConvo to ensure Solid storage is only used for Solid users - Fix saveConvoToSolid to merge updates with existing conversation data instead of overwriting - Preserve all conversation fields when only updating specific fields (e.g., title) - Fixes issue where conversation titles were not being saved to Solid Pod and where titles would revert to "untitled" after page refresh
- Add req parameter to duplicateConversation function for Solid storage support - Implement individual save operations for Solid users (saveConvo/saveMessage) - Maintain parent-child message relationships when duplicating - Use getMessagesFromSolid to retrieve messages from Solid Pod - Preserve existing bulk save approach for MongoDB users
- Added req parameter to deleteConvos function for Solid storage support - Implemented Solid storage deletion using deleteConvosFromSolid - Delete all associated messages when deleting conversations - Handle both single conversation and bulk deletion scenarios - Maintained MongoDB compatibility for non-Solid users
- Add support for archiving and unarchiving conversations stored in Solid Pods. - The isArchived field is now properly saved, retrieved, and filtered when fetching conversations for Solid-authenticated users.
Commented out several lines in conversation object construction and added TODOs for future enhancements.
- Added support for sharing conversations stored in Solid Pods by granting public read access via ACL (Access Control List) while preserving owner write permissions. This allows Solid users to share conversations while maintaining the ability to continue adding more messages to the conversation(write access)
- Added SolidIcon component for Solid authentication branding - Added Solid-specific configuration (solidLoginEnabled, solidLabel, solidImageUrl) - Added SOLID_OPENID_* environment variables for Solid authentication - Configure both Solid and generic OpenID strategies independently - Both buttons use the same /oauth/openid route and 'openid' strategy - Update TypeScript types to include Solid configuration fields This allows users to have separate "Login with Solid" and "Login with OpenID" buttons with different labels while maintaining the same authentication flow. The Solid button appears when SOLID_OPENID_* env vars are configured, and the OpenID button appears when OPENID_* env vars are configured (or when Solid is enabled, since they share the same strategy).
removed commented out code Co-authored-by: Jesse Wright <63333554+jeswr@users.noreply.github.com>
Co-authored-by: Jesse Wright <63333554+jeswr@users.noreply.github.com>
Co-authored-by: Jesse Wright <63333554+jeswr@users.noreply.github.com>
Co-authored-by: Jesse Wright <63333554+jeswr@users.noreply.github.com>
Co-authored-by: Jesse Wright <63333554+jeswr@users.noreply.github.com>
Co-authored-by: Jesse Wright <63333554+jeswr@users.noreply.github.com>
… writes - Run ensureBaseStructure in background after Solid/OpenID login (oauth handler) - Writes await baton so they don't run until base structure is ready - Lazy init if user never hit OAuth callback; return promise so .catch() is safe
There was a problem hiding this comment.
Pull request overview
This PR integrates Solid Pod storage for LibreChat, enabling users who log in via "Continue with Solid" to store conversations and messages in their personal Solid Pods instead of MongoDB. The implementation adds Solid-OIDC authentication, Pod storage operations, public sharing with ACL-based permissions, and maintains full backward compatibility with MongoDB for non-Solid users.
Changes:
- Added Solid-OIDC authentication flow with dedicated "Continue with Solid" button
- Implemented Solid Pod storage for conversations and messages with automatic container management
- Added public sharing functionality using manual ACL (Access Control List) for shared conversations
- Integrated storage backend selection based on authentication provider (Solid vs MongoDB)
- Added comprehensive conversation management (create, read, update, delete, duplicate, share) for Solid storage
Reviewed changes
Copilot reviewed 41 out of 43 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
api/server/services/SolidStorage.js |
Core Solid Pod operations including storage, retrieval, sharing, and ACL management |
api/server/utils/isSolidUser.js |
Helper to detect Solid login for storage routing |
api/models/Message.js |
Integrated Solid storage for messages with MongoDB fallback |
api/models/Conversation.js |
Integrated Solid storage for conversations with MongoDB fallback |
api/strategies/SolidOpenidStrategy.js |
Solid-OIDC authentication strategy implementation |
packages/data-schemas/src/methods/share.ts |
Updated share methods to support Solid Pod storage |
packages/data-provider/src/createPayload.ts |
Added payload normalization for Solid storage compatibility |
api/server/routes/share.js |
Updated share routes to pass request object for Solid support |
api/server/routes/config.js |
Added Solid configuration to startup config |
client/src/components/Auth/SocialLoginRender.tsx |
Added Solid login button with custom branding |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const sessionExpiry = Number(process.env.SESSION_EXPIRY) || DEFAULT_SESSION_EXPIRY; | ||
| const sessionOptions = { | ||
| secret: process.env.OPENID_SESSION_SECRET, | ||
| secret: process.env.SOLID_OPENID_SESSION_SECRET, |
There was a problem hiding this comment.
The session secret should use OPENID_SESSION_SECRET (generic) instead of SOLID_OPENID_SESSION_SECRET (Solid-specific) on line 89 to match the original code on line 59. Using different session secrets for Solid vs generic OpenID will cause session incompatibility issues.
| secret: process.env.SOLID_OPENID_SESSION_SECRET, | |
| secret: process.env.OPENID_SESSION_SECRET, |
| client_secret: process.env.SOLID_OPENID_CLIENT_SECRET, | ||
| }; | ||
|
|
||
| if (shouldGenerateNonce) { | ||
| clientMetadata.response_types = ['code']; | ||
| clientMetadata.grant_types = ['authorization_code']; | ||
| clientMetadata.token_endpoint_auth_method = 'client_secret_post'; |
There was a problem hiding this comment.
Solid pods using dynamic client registration should not require a client_secret. The presence of SOLID_OPENID_CLIENT_SECRET suggests static client registration, which is less secure and not aligned with Solid's recommended authentication flow. Consider implementing dynamic client registration without a client secret.
| client_secret: process.env.SOLID_OPENID_CLIENT_SECRET, | |
| }; | |
| if (shouldGenerateNonce) { | |
| clientMetadata.response_types = ['code']; | |
| clientMetadata.grant_types = ['authorization_code']; | |
| clientMetadata.token_endpoint_auth_method = 'client_secret_post'; | |
| }; | |
| if (shouldGenerateNonce) { | |
| clientMetadata.response_types = ['code']; | |
| clientMetadata.grant_types = ['authorization_code']; |
| res.send({ | ||
| '@context': ['https://www.w3.org/ns/solid/oidc-context.jsonld'], | ||
| redirect_uris: [process.env.DOMAIN_SERVER + process.env.OPENID_CALLBACK_URL], | ||
|
|
||
| // TODO: Don't hardcode path | ||
| client_id: process.env.DOMAIN_SERVER + '/solid-client-id', |
There was a problem hiding this comment.
The redirect_uris and client_id use OPENID_CALLBACK_URL instead of SOLID_OPENID_CALLBACK_URL. This will cause authentication failures when Solid and generic OpenID have different callback URLs configured.
| res.send({ | |
| '@context': ['https://www.w3.org/ns/solid/oidc-context.jsonld'], | |
| redirect_uris: [process.env.DOMAIN_SERVER + process.env.OPENID_CALLBACK_URL], | |
| // TODO: Don't hardcode path | |
| client_id: process.env.DOMAIN_SERVER + '/solid-client-id', | |
| const solidCallbackPath = | |
| process.env.SOLID_OPENID_CALLBACK_URL || | |
| process.env.OPENID_CALLBACK_URL || | |
| '/solid-client-id'; | |
| const solidClientIdUrl = (process.env.DOMAIN_SERVER || '') + solidCallbackPath; | |
| res.send({ | |
| '@context': ['https://www.w3.org/ns/solid/oidc-context.jsonld'], | |
| redirect_uris: [solidClientIdUrl], | |
| client_id: solidClientIdUrl, |
| @@ -46,10 +46,14 @@ router.get('/', async function (req, res) { | |||
|
|
|||
| const isOpenIdEnabled = | |||
| !!process.env.OPENID_CLIENT_ID && | |||
There was a problem hiding this comment.
The isOpenIdEnabled check is missing OPENID_CLIENT_SECRET validation, which is inconsistent with the original check that included it. This could allow incomplete OpenID configuration to be considered enabled.
| !!process.env.OPENID_CLIENT_ID && | |
| !!process.env.OPENID_CLIENT_ID && | |
| !!process.env.OPENID_CLIENT_SECRET && |
Use Promise.all over messageFiles so getFile + file.text() run in parallel instead of sequentially; keep per-file error handling and validation.
api/server/services/SolidStorage.js
Outdated
| const promise = (async () => { | ||
| try { | ||
| const { authenticatedFetch, podUrl } = await getSolidFetchAndPodUrl(req); | ||
| await ensureBaseStructure(podUrl, authenticatedFetch); | ||
| logger.debug('[SolidStorage] Base structure ready after login', { openidId }); | ||
| } catch (err) { | ||
| baseStructureBatonMap.delete(openidId); | ||
| logger.warn('[SolidStorage] Base structure init after login failed', { | ||
| openidId, | ||
| error: err?.message, | ||
| }); | ||
| throw err; | ||
| } | ||
| })(); | ||
| baseStructureBatonMap.set(openidId, promise); | ||
| return promise; |
There was a problem hiding this comment.
You can just call ensureBaseStructureReady here - no need to repeat the logic.
There was a problem hiding this comment.
I have pushed this commit: d98aa69 to address this
Co-authored-by: Jesse Wright <63333554+jeswr@users.noreply.github.com>
PR'ing the work done by @langsamu and @PreciousOritsedere to add Solid Login and Chat Management to Librechat to the main branch of the
solidfork to enable internal review before upstreaming.