Skip to content

Add PDF streaming viewer and token caching#174

Open
akashroy8210 wants to merge 3 commits into
devfrom
feature/pdf-viewer-streaming
Open

Add PDF streaming viewer and token caching#174
akashroy8210 wants to merge 3 commits into
devfrom
feature/pdf-viewer-streaming

Conversation

@akashroy8210

Copy link
Copy Markdown

Changes

  • Added backend PDF viewing endpoint.
  • Streams PDFs from Microsoft Graph instead of redirecting users to the OneDrive preview page.
  • Eliminates repeated OneDrive authentication prompts.
  • Added access token caching to reduce request latency.
  • Opens PDFs in a new browser tab using the browser's native PDF viewer.

Performance

Observed timings after caching:

  • MongoDB lookup: ~5–15ms
  • Access token retrieval: ~0–5ms (cached)
  • Microsoft Graph fetch: ~700–800ms
  • End-to-end PDF open time: typically under 1 second

User Impact

Users can now open PDFs directly in a new browser tab without being redirected to OneDrive or repeatedly authenticating.

@akashroy8210 akashroy8210 requested a review from DreamBot706 June 19, 2026 06:10
@RsbhThakur RsbhThakur linked an issue Jul 3, 2026 that may be closed by this pull request
@RsbhThakur RsbhThakur self-requested a review July 3, 2026 06:17
Comment thread client/src/screens/browse/components/file-display/index.jsx Outdated
Comment thread client/src/screens/browse/components/file-display/index.jsx

@RsbhThakur RsbhThakur left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Many critical issues with this PR. please fix all before merging.

Comment thread server/modules/contribution/contribution.controller.js Outdated
Comment thread server/modules/contribution/contribution.controller.js Outdated
Comment thread server/modules/contribution/contribution.controller.js Outdated
Comment thread server/modules/contribution/contribution.controller.js
Comment thread server/modules/onedrive/onedrive.controller.js Outdated
Comment thread server/modules/onedrive/onedrive.controller.js Outdated
Comment thread server/modules/onedrive/onedrive.controller.js Outdated
Comment thread server/services/UploadFile.js Outdated
@akashroy8210 akashroy8210 requested a review from RsbhThakur July 11, 2026 16:07

@akashroy8210 akashroy8210 left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The update removes unnecessary debug logs, adds safer OneDrive access-token refresh handling, preserves the streamed file content type, and fixes the Authorization header format.

@RsbhThakur RsbhThakur left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Kindly fix the issues mentioned in the comment, and review it once yourself, also create a changelog with complete details and comment it here so that reviewing would be easy next time. Not mergeable until the issues get fix.

router.post("/updated", catchAsync(ContributionController.GetContributionsUpdatedSince));
router.post("/br",isAuthenticated, ContributionController.GetBrContribution)

router.get('/view/:id',catchAsync(ContributionController.viewFile))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Security Vulnerability: This route is currently unprotected. There is no isAuthenticated middleware applied to it. Since the browser automatically sends cookie credentials for window.open tabs, this route should be protected. Otherwise, any unauthenticated user or external script can access and download files directly from the server.

}
window.open(preview_url, "_blank");
window.open(
`${API_BASE_URL}/api/contribution/view/${file._id}`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Functional Regression (Office Documents): Opening the backend streaming URL works great for PDFs and images (which browsers can render inline natively). However, browsers cannot render Office files (like .docx, .xlsx, .pptx) natively.

Previously, clicking "View" on a .docx file opened Microsoft's web viewer (file.webUrl) so the user could read it online. Now, this change forces a raw binary download of the Office file. We should only use the backend stream proxy if the file type is strictly a PDF, falling back to the original webUrl for other formats.

}
}

async function viewFile(req, res, next) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing Authorization Check & Resource Leaks:

There are three issues with this controller:

  1. Access Bypass: There is no verification check. A regular user (non-BR) can access and download unverified files (file.isVerified === false) if they know the MongoDB ID, bypassing the BR curation block. Please check the file status and verify the user's role before streaming.
  2. Connection Leaks: If a user closes their tab or cancels the download mid-stream, the response connection terminates but the incoming Graph API stream remains open. We need to handle the request close event to destroy the incoming Axios stream and free up sockets.
  3. Missing Size Metadata: Only the Content-Type header is set on the response. Without the Content-Length header, the browser's PDF viewer won't display a loading progress bar or estimate total pages.

let cachedAccessToken = null;
let tokenExpiry = 0;
let refreshPromise = null;
export async function getAccessToken() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Robustness Issue (No Cache Eviction on 401):

Caching the token in memory to avoid duplicate Graph API authorization round-trips is a massive performance win.

However, if the cached token is invalidated or revoked on Microsoft's end before the local expiration (tokenExpiry) is reached, Microsoft will return a 401 Unauthorized. Since the cache never evicts the token on authorization failure, the server will continue to reuse the dead token and return errors to all users until the full hour expires. We need a way to invalidate the cache immediately upon hitting a 401 error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

File view (2)

3 participants