Skip to content

feat: implement MDBList OAuth 2.0 Device Code flow - #738

Open
Himanth-reddy wants to merge 7 commits into
ProdigyV21:mainfrom
Himanth-reddy:feat/mdblist-oauth-device-flow
Open

Himanth-reddy wants to merge 7 commits into
ProdigyV21:mainfrom
Himanth-reddy:feat/mdblist-oauth-device-flow

Conversation

@Himanth-reddy

Copy link
Copy Markdown
Collaborator

Summary

Implements the standard OAuth 2.0 Device Code flow (RFC 8628) for MDBList across Android TV and mobile platforms, bringing it into parity with the Trakt and Simkl device linking experiences while removing legacy manual API key entry.

Changes

  • API & Networking (MdbListApi.kt):
    • Added oauth/device-authorization/ endpoint for requesting device code, user code, and verification URI.
    • Added oauth/token/ endpoint for polling token exchange.
    • Added authorization models (MdbDeviceAuthorizationResponse, MdbDeviceTokenRequest, MdbTokenResponse).
    • Added @Header("Authorization") support to all MDBList API endpoints.
  • Persistence & Store (SyncProviderStore.kt):
    • Added per-profile DataStore storage for mdblist_access_token, mdblist_refresh_token, and mdblist_token_expires_at.
    • Added backward-compatible fallback for existing API keys and updated provider connection detection.
  • Repository & Polling (MdbListRepository.kt, SettingsViewModel.kt):
    • Added device code initialization and polling routines with standard OAuth error handling (authorization_pending, slow_down, expired_token, access_denied).
    • Added clean cancellation on dismiss or disconnect.
  • TV & Mobile UI (SettingsScreen.kt):
    • Wired MDBList into TraktActivationModal dialog with QR code and external browser launch.
    • Formatted activation instruction URL to display cleanly up to /device (https://mdblist.com/oauth/device), omitting query parameters while keeping full URL for QR code and browser buttons.
    • Cleaned up background AccountRow / TrackingServiceRow to avoid inline text expansion and spinners while the modal dialog is open in the foreground.
    • Removed manual API key dialog and input fields.
  • Secrets & Configuration (Constants.kt, secrets.defaults.properties):
    • Added MDBLIST_CLIENT_ID configuration key.

Verification

  • Built debug sideload build: ./gradlew :app:assembleSideloadDebug -PincludeX86Abis=true — Successful.
  • Tested on Android TV (emulator-5556) and Android Phone (emulator-5554).
  • Updated AST knowledge graph via graphify update ..

@github-actions github-actions Bot added the area: android Changes to the Android app or Gradle build label Sep 21, 2026
- Implement standard OAuth 2.0 Device Authorization Grant for MDBList
- Add device code request and polling token endpoints in MdbListApi
- Store per-profile OAuth bearer token, refresh token, and expiration in SyncProviderStore
- Integrate device authorization modal with QR code on TV and mobile
- Sanitize activation instruction URL to display cleanly up to /device without query params
- Clean up background account rows to avoid inline auth text and background spinners during authentication
- Remove manual API key input dialogs and legacy validation logic
@Himanth-reddy
Himanth-reddy force-pushed the feat/mdblist-oauth-device-flow branch from 2052768 to 71c50c4 Compare September 24, 2026 10:17
@ProdigyV21

Copy link
Copy Markdown
Owner

Thanks for working on this, Himanth. QR-code login would make MDBList much easier to connect on TV. The rebase has resolved the earlier merge conflicts, but let's keep this open until the authentication lifecycle is complete.

These are the remaining issues I found:

  1. Token renewal: The refresh token and expiry are stored, but no request path uses them to renew the access token. Add serialized renewal, preserve the refresh token when a response omits it, and handle renewal failures without crashing or claiming success.
  2. Disconnect: Clearing only OAuth tokens leaves an existing API key active. Clear both credential types. Cloud disconnect/import must also clear stale OAuth credentials, not just mdblist_api_key.
  3. Cloud and web compatibility: OAuth access tokens are currently exported as mdbListApiKey, without the refresh token or expiry. Keep API keys and OAuth credentials distinct, sync the complete credential, and update Android, the backend's timestamp-based credential merge, and the webapp together. The web proxy currently sends only ?apikey=, so it does not support the new bearer-token login.
  4. Client ID and fallback: We don't currently have a confirmed registered MDBList client ID for ARVIO. Please confirm the registration/configuration needed for release builds. Keep the existing API-key login available until OAuth is configured and verified, otherwise removing that dialog leaves new users unable to connect.
  5. Request authentication: The repository currently sends the same credential as both Authorization: Bearer ... and ?apikey=.... Send OAuth tokens only in the authorization header and legacy API keys only as API keys.
  6. Device polling: Parse the OAuth error response once. Handle slow_down, access_denied, and expired_token by their error codes, including HTTP 400 responses. The current code only backs off on 429 and can miss standard device-flow responses.
  7. Profile safety: Bind login/polling and token renewal to the profile that started them. Cancel on profile switch and prevent an in-flight response from reconnecting a disconnected account or saving credentials into another profile.
  8. Unrelated UI changes: Please retain Trakt/Simkl's existing working indicators and cancellation behavior. Several rows now hardcode isWorking = false; this MDBList change shouldn't regress those integrations.

Please add tests for expiry/renewal, legacy-key disconnect, cloud round-trips and disconnects, polling errors, and profile switches. Then verify actual device-code login and cross-device/web behavior with the registered client ID. A successful initial login alone doesn't cover these cases.

I stopped my local fix attempt and discarded those edits. Nothing has been pushed or merged from that attempt; your PR and commits remain unchanged.

…ist OAuth lifecycle

- Serialize token renewal via Mutex in MdbListRepository, preserving refresh tokens on omission and handling renewal errors gracefully
- Separate OAuth (Authorization: Bearer <token>) from legacy API key (?apikey=<key>) across Android, web proxy, and web tracking client
- Ensure complete disconnect clears both OAuth and API key credentials across local storage and cloud sync
- Restore manual API key connect dialog and fallback when MDBList client ID is absent
- Fix device polling error parsing using single read of errorBody and RFC 8628 code handling
- Enforce profile scoping during polling and token renewal to prevent cross-profile pollution
- Restore Trakt and Simkl isWorking indicators and cancellation callbacks in SettingsScreen
- Add MdbListAuthLifecycleTest unit test suite covering renewal serialization, omission preservation, disconnect, error parsing, and auth separation
- Add Netlify cloud sync push test for MDBList OAuth credentials
@github-actions github-actions Bot added the area: web Changes to web or Netlify sites label Sep 25, 2026
@github-actions github-actions Bot added documentation Improvements or additions to documentation area: ci Changes to CI/CD and repository automation labels Sep 27, 2026
@ProdigyV21

Copy link
Copy Markdown
Owner

Thanks, Himanth. I pushed the remaining code fixes to this PR, preserving your original commits and authorship.

Fixed the merge with current main; guarded Android refresh against disconnect/new-login races; kept provider changes bound to the correct profile; added web renewal and OAuth support for watched history/watchlist writes; preserved API-key fallback; fixed the TV fallback button handling; and wired the existing MDBLIST_CLIENT_ID repository secret into signed Android and web builds. Failed authentication is no longer treated as a successfully empty Android watchlist.

Local verification passed: 26 Android authentication/store tests, 743 web tests, 113 backend tests, TypeScript checks, and diff checks. GitHub CI is running on the updated head.

One external check still needs confirming before I merge: actual device-code authorization and refresh using ARVIO's registered public MDBList client, without embedding a client secret. The repository secret exists, but that alone does not establish that the client is registered for these grants. Could you confirm the public client ID/registration and test a real TV login, renewal, and web/cloud restore? Please do not post a client secret or user tokens. I added docs/MDBLIST_OAUTH.md with the configuration and live-check checklist.

Leaving this open until that is verified; the automated tests use synthetic credentials and cannot establish live MDBList authorization.

# Conflicts:
#	app/src/main/kotlin/com/arflix/tv/ui/screens/settings/SettingsViewModel.kt
Himanth-reddy added a commit to Himanth-reddy/ARVIO that referenced this pull request Sep 27, 2026
Himanth-reddy added a commit to Himanth-reddy/ARVIO that referenced this pull request Sep 27, 2026
@Himanth-reddy

Copy link
Copy Markdown
Collaborator Author

I have tested and verified live MDBList OAuth 2.0 device authorization, real TV login, and watch history synchronization on Android TV (emulator-5554) with the registered public MDBList client:

  1. Rebase & Parity with Latest main:

  2. Live TV Device Code Linking:

    • Initiated MDBList linking from Settings > Accounts.
    • Displayed standard device linking modal with user code (S1MTV98E), QR code, and instruction URL (https://mdblist.com/oauth/device).
    • Completed authorization on MDBList. Polling exchanged the user code for credentials and updated status to CONNECTED without requiring a manual API key.
  3. Live Sync & History Verification:

    • Confirmed live account synchronization with mdblist.com (@himanth421).
    • Up Next / Watch tracking for titles (e.g., MobLand) correctly synchronized across the MDBList web dashboard and ARVIO Android TV with full rating badges (IMDb, RT, Metacritic, Trakt).

Live Verification Screenshots

MDBList Device Code Dialog Accounts - Connected
Media Details & Ratings (TV) MDBList Web Dashboard
MobLand Watched Sync (TV)

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

Labels

area: android Changes to the Android app or Gradle build area: ci Changes to CI/CD and repository automation area: web Changes to web or Netlify sites documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants