Skip to content

Conversation

@mikouaji
Copy link
Contributor

@mikouaji mikouaji commented Feb 10, 2026

This feature extends the npmx connector functionality for handling authorization with 2fa keys configured in npm account settings.
This works by allowing running the npm commands within an interactive shell which does not prompt for OTP but rather asks to verify auth on a web page.

I have added some settings to the connector modal:

  • Use web auth - enables the feature
  • Auto open auth page - opens the auth page automatically in a new tab

Currently tested only on linux
Needs testing on Windows and Mac

Preview before connecting (in Advanced options):
web_auth_settings_disconnected

Preview after connecting:
web_auth_settings_connected

Some previews of it in action:

web_auth_auto_url.mp4
web_auth_no_auto_url.mp4
web_auth_otp_with_web_after.mp4

FYI @neutrino2211 I was supposed to tag you here ;)

@vercel
Copy link

vercel bot commented Feb 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
npmx.dev Ready Ready Preview, Comment Feb 10, 2026 11:52pm
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs.npmx.dev Ignored Ignored Preview Feb 10, 2026 11:52pm
npmx-lunaria Ignored Ignored Feb 10, 2026 11:52pm

Request Review

@github-actions
Copy link

github-actions bot commented Feb 10, 2026

Lunaria Status Overview

🌕 This pull request will trigger status changes.

Learn more

By default, every PR changing files present in the Lunaria configuration's files property will be considered and trigger status changes accordingly.

You can change this by adding one of the keywords present in the ignoreKeywords property in your Lunaria configuration file in the PR's title (ignoring all files) or by including a tracker directive in the merged commit's description.

Tracked Files

File Note
lunaria/files/en-GB.json Localization changed, will be marked as complete.
lunaria/files/en-US.json Source changed, localizations will be marked as outdated.
lunaria/files/pl-PL.json Localization changed, will be marked as complete.
Warnings reference
Icon Description
🔄️ The source for this localization has been updated since the creation of this pull request, make sure all changes in the source have been applied.

@danielroe
Copy link
Member

this is beautiful

@neutrino2211
Copy link
Contributor

Will pull and test on MacOS in a bit. Thanks a ton! Auth issues have been a pain

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 10, 2026

📝 Walkthrough

Walkthrough

Adds browser-based connector authentication and related UI flows: ConnectorModal and OperationsQueue now surface connector.webAuth and connector.autoOpenURL, open auth URLs and poll for completion; settings schema and defaults extended. The connector composable and server/comms propagate interactive/openUrls flags and authUrl; CLI gains PTY-driven interactive npm execution, URL extraction, onAuthUrl callbacks and options-based exec APIs; types updated to carry authUrl and collected urls. i18n keys and TypeScript typings for node-pty were added.

Possibly related PRs

Suggested reviewers

  • danielroe
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The PR description clearly explains the feature: extending npmx connector to support web-based 2FA authentication for npm accounts, with new settings for enabling web auth and auto-opening auth pages.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (1)
app/components/Org/OperationsQueue.vue (1)

68-78: Consider extracting a shared retry helper.

handleRetryWithOtp and handleRetryWithWebAuth duplicate the OTP-failed retry loop; a small helper would keep the flow DRY.

@mikouaji
Copy link
Contributor Author

🤦 as always tests need fixing, looking into them

@codecov
Copy link

codecov bot commented Feb 10, 2026

Codecov Report

❌ Patch coverage is 33.92857% with 37 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
app/components/Header/ConnectorModal.vue 36.95% 22 Missing and 7 partials ⚠️
app/components/Org/OperationsQueue.vue 11.11% 7 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
app/components/Org/OperationsQueue.vue (1)

68-78: Optional: dedupe retry logic.
handleRetryWithWebAuth and handleRetryWithOtp share the same retry loop; a small helper would reduce drift.

♻️ Possible refactor
+async function retryOtpFailedOps(): Promise<void> {
+  const otpFailedOps = activeOperations.value.filter(
+    (op: PendingOperation) => op.status === 'failed' && op.result?.requiresOtp,
+  )
+  for (const op of otpFailedOps) {
+    await retryOperation(op.id)
+  }
+}
+
 async function handleRetryWithOtp() {
   if (!otpInput.value.trim()) return
   const otp = otpInput.value.trim()
   otpInput.value = ''
-  const otpFailedOps = activeOperations.value.filter(
-    (op: PendingOperation) => op.status === 'failed' && op.result?.requiresOtp,
-  )
-  for (const op of otpFailedOps) {
-    await retryOperation(op.id)
-  }
+  await retryOtpFailedOps()
   await handleExecute(otp)
 }
 
 async function handleRetryWithWebAuth() {
-  const otpFailedOps = activeOperations.value.filter(
-    (op: PendingOperation) => op.status === 'failed' && op.result?.requiresOtp,
-  )
-  for (const op of otpFailedOps) {
-    await retryOperation(op.id)
-  }
+  await retryOtpFailedOps()
   await handleExecute()
 }
cli/src/npm-client.ts (1)

168-301: Consider splitting execNpmInteractive into helpers.
This function is well structured but quite long; extracting pieces (spawn setup, onData handling, finalise result) would improve maintainability.

As per coding guidelines, "Keep functions focused and manageable (generally under 50 lines)".

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
cli/src/npm-client.ts (1)

217-258: Consider disposing event subscriptions to prevent potential memory leaks.

The onData and onExit methods return IDisposable objects that should be disposed when no longer needed. While the PTY process exits anyway, explicitly disposing these subscriptions is a best practice, especially if this code is later adapted for long-running scenarios.

Proposed refactor
+    const dataDisposable = child.onData((data: string) => {
-    child.onData((data: string) => {
       output += data
       // ... rest of handler
     })

+    const exitDisposable = child.onExit(({ exitCode }) => {
-    child.onExit(({ exitCode }) => {
       if (resolved) return
       resolved = true
       clearTimeout(timeout)
       if (authUrlTimeout) clearTimeout(authUrlTimeout)
+      dataDisposable.dispose()
+      exitDisposable.dispose()

       // ... rest of handler
     })

@mikouaji
Copy link
Contributor Author

@danielroe fixed all tests etc

@danielroe
Copy link
Member

tested this and seemed to work well on MacOS - in fact I think it could be the default (maybe even non-configurable?) and only if it fails should we fall back to OTP...

@neutrino2211
Copy link
Contributor

Just checked it out. The UX is very clean and the connector isn't giving issues straight away.

Your org management UI is also way better than what I was planning so i think this addresses #34 as well

@neutrino2211
Copy link
Contributor

tested this and seemed to work well on MacOS - in fact I think it could be the default (maybe even non-configurable?) and only if it fails should we fall back to OTP...

Yeah, I'm onboard with this

@danielroe
Copy link
Member

danielroe commented Feb 11, 2026

I don't think this PR touched the org management UI - I think that's back from some time ago.

@mikouaji
Copy link
Contributor Author

in fact I think it could be the default (maybe even non-configurable?) and only if it fails should we fall back to OTP

I can make it work this way, we just need a clean way of handling it, currently there is a 90s timeout if the link is not clicked. Other than that only happy cases work pretty well, other failures still need to be covered.

Your org management UI is also way better than what I was planning so i think this addresses #34 as well

Yeah, nothing was changed there, you must be seeing the UI from before you did anything.

@mikouaji
Copy link
Contributor Author

What about the auto opening setting? I'd leave it so people can choose, some might not like tabs appearing suddenly.

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.

3 participants