Skip to content

Migrate Nexus auth to OAuth 2.0 PKCE#18

Merged
spikehockey75 merged 7 commits intomainfrom
feature/nexus-oauth2-pkce
Mar 12, 2026
Merged

Migrate Nexus auth to OAuth 2.0 PKCE#18
spikehockey75 merged 7 commits intomainfrom
feature/nexus-oauth2-pkce

Conversation

@spikehockey75
Copy link
Owner

@spikehockey75 spikehockey75 commented Mar 1, 2026

Summary

  • Replace deprecated WebSocket SSO + API key auth with OAuth 2.0 PKCE flow for Nexus Mods, using a localhost callback server (port 9876) and short-lived access tokens with automatic refresh
  • New nexus_oauth.py handles PKCE code challenge, browser-based authorization, token exchange, JWT user info extraction, and token refresh — replaces deleted nexus_sso.py
  • All API consumers updated to use Bearer token auth with transparent auto-refresh, legacy nexus_api_key config entries auto-migrated on startup
  • README updated with new description, OAuth references, and removed websocket-client dependency

Changed Files

File Change
app/services/nexus_oauth.py New — PKCE flow, localhost callback, token refresh, JWT decode
app/services/nexus_sso.py Deleted — replaced by nexus_oauth.py
app/config/config_manager.py OAuth token storage, expiry check, legacy migration
app/services/nexus_service.py Bearer auth header, auto-refresh via _ensure_token()
app/ui/nexus_widget.py OAuth dialog, token validation/refresh workers
app/ui/tabs/mods_tab.py Token swap, config capture fixes
app/ui/dialogs/add_mod_dialog.py Token swap
app/ui/main_window.py Token swap
app/ui/dialogs/settings_dialog.py Remove API key field, show connection status
build/build.py Swap hidden import to nexus_oauth
requirements.txt Remove websocket-client
README.md Updated description, OAuth references

Test plan

  • Launch app — "Connect Account" button visible (old API key cleared on migration)
  • Click "Connect Account" — browser opens to Nexus authorize page
  • Authorize in browser — app captures code, shows username + premium/free status
  • Close and reopen app — still logged in (tokens persisted)
  • Install/update a mod — Bearer token used in all Nexus API calls
  • Verify auto-refresh works when token expires
  • Verify revoked token clears auth and shows "Connect Account" again

🤖 Generated with Claude Code

spikehockey75 and others added 7 commits March 1, 2026 10:06
Migrate Nexus Mods authentication from legacy API key + WebSocket SSO
to industry-standard OAuth 2.0 with PKCE for improved security and
future-proofing against API key deprecation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the deprecated API key + WebSocket SSO flow with industry-standard
OAuth 2.0 PKCE for desktop apps. Short-lived access tokens with automatic
refresh replace the old permanent API key. Bearer token auth on all API
requests, JWT-based user info extraction, and localhost callback server
on port 9876 for the authorization code exchange.

- Add app/services/nexus_oauth.py (PKCE flow, callback server, token refresh)
- Remove app/services/nexus_sso.py (deprecated WebSocket SSO)
- Update config_manager with OAuth token storage and legacy migration
- Update nexus_service with Bearer auth and auto-refresh
- Rewrite nexus_widget OAuth dialog and token validation
- Update all API consumers (mods_tab, add_mod_dialog, main_window, settings_dialog)
- Remove websocket-client dependency
- Update README to reflect OAuth 2.0 changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Auto-open the OAuth dialog on first launch when not logged in, with an
info banner explaining that update checks, trending mods, and Nexus
downloads require sign-in. Fix deadlock when cancelling the auth dialog
by replacing server.shutdown() with server_close() to unblock the
handle_request() loop.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add User-Agent header to OAuth token requests to prevent Cloudflare
  error 1010 blocking Python's default urllib agent string
- Fetch user avatar via Nexus v2 GraphQL API after login since the JWT
  and v1 validate endpoint don't provide it
- Fix QThread destroyed-while-running crash by adding _start_bg_work
  helper that waits for previous threads before starting new ones

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add periodic silent renew timer (every 5 min) that refreshes the
  OAuth token when it's within 10 minutes of expiry
- Show info message when user skips first-launch sign-in, explaining
  that update checks, trending mods, and downloads require auth
- Fetch user avatar via Nexus v2 GraphQL API using member ID from JWT
- Remove debug print statements from OAuth and widget code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Check installed ME3 version against latest GitHub release on startup
- Show clickable "Update to vX.Y.Z" button in sidebar when outdated
- Add ME3 Update dialog with download progress bar
- Add "Check for ME3 Updates" button in Settings dialog
- Fix version normalization to handle "me3 0.x.x" prefix from CLI
- Show green version labels in sidebar when app and ME3 are up to date
- Check app version against latest release on startup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@spikehockey75 spikehockey75 merged commit 7d03174 into main Mar 12, 2026
3 checks passed
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.

1 participant