-
Notifications
You must be signed in to change notification settings - Fork 501
Description
Problem
1Code is currently preventing other Electron applications from handling their own OAuth/PKCE authentication flows. This happens even when 1Code is not even running.
What's Happening
- When users click OAuth redirect links for OTHER Electron apps in their browser, the browser shows "Open Electron" and 1Code opens instead of the intended app
- OAuth authentication fails with "Invalid or expired auth code" errors because the auth code was meant for a different app
- This blocks other developers' Electron apps from working correctly
- The issue persists even after closing 1Code or removing
node_modules
Why This Is Happening
1Code is registering custom protocols (twentyfirst-agents://) at the macOS system level in two problematic ways:
-
electron-builderProtocol Registration: Theprotocolssection inpackage.jsoncreates permanent OS-level associations in macOS LaunchServices that persist even after 1Code is closed or uninstalled. -
Non-Unique userData Path: The
app.requestSingleInstanceLock()uses a genericuserDatapath that creates lock files interfering with other Electron applications.
Required Fixes
The following code changes must be implemented to stop 1Code from blocking other apps:
1. Remove OS-Level Protocol Registration
Action Required: Delete the protocols section from package.json to stop 1Code from registering at the OS level:
"build": {
"appId": "dev.21st.agents",
"productName": "1Code",
"npmRebuild": true,
- "protocols": [
- {
- "name": "1Code",
- "schemes": [
- "twentyfirst-agents"
- ]
- }
- ],
"directories": {
"buildResources": "build",
"output": "release"
}
}2. Stop Registering Protocols in Development
Action Required: Modify src/main/index.ts to skip protocol registration during development:
function registerProtocol(): boolean {
+ // Skip protocol registration in development to prevent blocking other apps
+ if (IS_DEV) {
+ console.log("[Protocol] Skipping registration in dev mode to avoid blocking other apps")
+ return false
+ }
+
let success = false
if (process.defaultApp) {
// Dev mode: need to pass execPath and script path
if (process.argv.length >= 2) {
success = app.setAsDefaultProtocolClient(PROTOCOL, process.execPath, [
process.argv[1]!,
])
}
} else {
// Production mode
success = app.setAsDefaultProtocolClient(PROTOCOL)
}
return success
}3. Clean Up Protocol Registration on Quit
Action Required: Add cleanup code in src/main/index.ts to unregister the protocol handler when 1Code closes:
/**
* Unregister the protocol handler when app quits
* This prevents blocking other Electron apps
*/
function unregisterProtocol(): void {
if (IS_DEV) {
return // Skip in dev mode since we didn't register
}
try {
app.removeAsDefaultProtocolClient(PROTOCOL)
console.log("[Protocol] Unregistered protocol handler")
} catch (error) {
console.warn("[Protocol] Failed to unregister:", error)
}
}
// Register the cleanup handler
app.on("will-quit", () => {
unregisterProtocol()
})4. Fix userData Path to Be App-Specific
Action Required: Change the userData path in src/main/index.ts to be unique to 1Code:
if (IS_DEV) {
const { join } = require("path")
- const devUserData = join(app.getPath("userData"), "..", "Agents Dev")
+ // Use appId-specific path to avoid conflicts with other Electron apps
+ const devUserData = join(app.getPath("userData"), "..", "21st-dev-agents-dev")
app.setPath("userData", devUserData)
console.log("[Dev] Using separate userData path:", devUserData)
}Cleanup Steps for Users Affected by This Bug
If 1Code has already blocked other Electron apps, users need to manually clean up the OS-level registrations. Here's how:
Step 1: Backup Your LaunchServices Preferences
cp ~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist \
~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist.backupStep 2: Remove 1Code's Protocol Entries from LaunchServices
# Convert plist to XML for editing
plutil -convert xml1 ~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist \
-o /tmp/launchservices_edit.plist
# Remove the protocol entries using Python
python3 << 'EOF'
import plistlib
# Read the plist
with open('/tmp/launchservices_edit.plist', 'rb') as f:
plist = plistlib.load(f)
# Remove 1Code's protocol entries
if 'LSHandlers' in plist:
original_count = len(plist['LSHandlers'])
plist['LSHandlers'] = [
handler for handler in plist['LSHandlers']
if handler.get('LSHandlerURLScheme') not in ['twentyfirst-agents', 'twentyfirst-agents-dev']
]
removed_count = original_count - len(plist['LSHandlers'])
print(f"Removed {removed_count} entries")
# Write back
with open('/tmp/launchservices_cleaned.plist', 'wb') as f:
plistlib.dump(plist, f)
print("Cleaned plist saved")
else:
print("No LSHandlers found")
EOF
# Convert back to binary and replace original
plutil -convert binary1 /tmp/launchservices_cleaned.plist \
-o ~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plistStep 3: Clean Up 1Code's Caches and Data
# Remove 1Code's caches
rm -rf ~/Library/Caches/dev.21st.agents
rm -rf ~/Library/Caches/dev.21st.agents.ShipIt
# Remove 1Code's userData directory
rm -rf ~/Library/Application\ Support/21st-dev-agents-devStep 4: Unregister 1Code's Development Electron.app
# Unregister 1Code's Electron.app from node_modules
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister \
-u "/path/to/1code/node_modules/electron/dist/Electron.app"Step 5: Restart Dock
killall DockStep 6: Verify 1Code's Protocols Are Removed
# Check if 1Code's protocols are still registered
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister \
-dump 2>&1 | grep -i "twentyfirst-agents"
# Should return no results or minimal cached entriesTroubleshooting
Other Apps Are Still Being Blocked
If 1Code is still blocking other Electron apps after the cleanup:
-
Restart your Mac - LaunchServices caches can be stubborn and may require a full system restart to clear completely.
-
Check for mounted 1Code DMG volumes - If a 1Code installer DMG is mounted, it's still registered:
# Find mounted 1Code volumes /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister \ -dump 2>&1 | grep -B20 "twentyfirst-agents" | grep "path:" # Unmount any 1Code DMG volumes hdiutil detach "/Volumes/1Code*"
-
Remove installed 1Code from /Applications:
rm -rf /Applications/1Code.app
-
Rebuild LaunchServices database (use with caution):
# This will rebuild the entire LaunchServices database /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister \ -kill -r -domain local -domain user
Note: The
-killoption has been removed in recent macOS versions, so this may not work on newer systems.
Verify Other Apps Work Again
- Click an OAuth link for another Electron app in your browser
- Verify the correct app opens (not 1Code)
- Confirm the OAuth flow completes successfully
Best Practices to Prevent This
- Never register protocols in development mode - Only register in production builds to avoid blocking other developers' apps
- Use app-specific userData paths - Include your app ID to prevent single instance lock conflicts
- Always clean up on quit - Unregister protocol handlers when the app closes
- Avoid
electron-builderprotocol registration - Handle protocols at runtime, not build time - Prefer localhost callbacks - For OAuth flows, use
http://localhostredirect URIs instead of custom schemes when possible
Related Issues
- Electron #18728 - Allow running single instance for all applications
- Electron Deep Links Documentation
Environment
- OS: macOS (issue also affects Windows and Linux)
- Electron Version: Any version using
app.setAsDefaultProtocolClient() - Build Tool: electron-builder
Impact
This bug completely breaks OAuth flows for other Electron applications. Developers running multiple Electron apps cannot authenticate because 1Code intercepts their auth callbacks. The OS-level protocol registration persists across app restarts and even after uninstalling 1Code, making it extremely difficult to debug.
Fixing this requires:
- Code changes in 1Code (to stop future registrations)
- Manual cleanup by affected users (to remove existing registrations)