Skip to content

feat: add headless MSA credentials login - #18

Open
HashimTheArab wants to merge 1 commit into
lunarfrom
feat/msa-credentials
Open

feat: add headless MSA credentials login#18
HashimTheArab wants to merge 1 commit into
lunarfrom
feat/msa-credentials

Conversation

@HashimTheArab

@HashimTheArab HashimTheArab commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a headless Microsoft-account username/password login flow to the sisu package: Config.CredentialsToken(ctx, email, password) (*oauth2.Token, error). This is the one capability go-xsapi lacked versus RaphiMC/MinecraftAuth. The returned *oauth2.Token plugs straight into the existing SISU/Xbox Live flow (e.g. Config.TokenSource, Config.New).

It ports MinecraftAuth's CredentialsMsaAuthService for the LIVE (login.live.com) environment.

Flow

  1. GET oauth20_authorize.srf with client_id, scope (the existing MBI_SSL scope const), redirect_uri=https://login.live.com/oauth20_desktop.srf, response_type=code, response_mode=query, over an HTTP client with a cookie jar. The desktop redirect is used (instead of Config.RedirectURI, which is an ms-xal:// scheme) so the final code is readable from the URL.
  2. Scrape var ServerData = {...} out of the returned HTML and decode it, pulling urlPost and the sFTTag PPFT hidden-input (field name + value).
  3. POST form-urlencoded login, loginfmt, passwd, PPFT to urlPost, following redirects (the cookie jar carries the session).
  4. Read the authorization code from the terminal oauth20_desktop.srf?code=... URL (resp.Request.URL). If it instead lands on a login/interrupt page, the embedded ServerData error (sErrorCode/sErrTxt) or a DoSubmit interrupt dialog is surfaced as a clear error.
  5. Exchange the code for the token (mirrors Config.Exchange, adding scope/client_id, with redirect_uri pinned to the desktop URI so Microsoft accepts the exchange).

The cookie-jar client is a shallow copy of the context client with only Jar added — the caller's Transport/Timeout are preserved and the caller's client is never mutated.

Testing

  • Unit tests for every pure helper (extractServerData, parsePPFT, codeFromURL, redirectError, loginError) with realistic fixture strings, including a realistic ServerData HTML snippet, a PPFT sFTTag, a desktop.srf redirect URL with a code, and error/interrupt pages.
  • An end-to-end httptest.Server test covering the full authorize → POST → redirect → code-extraction → token-exchange path (fake oauth20_authorize.srf, urlPost, oauth20_desktop.srf, and oauth20_token.srf).
  • A second end-to-end test covering the wrong-credentials error path.
  • No test makes a real network call (the authorize/token endpoints are overridable via unexported package vars for tests only; the public API is unchanged).

gofmt -s, go build ./..., go vet ./xal/sisu/, and go test ./xal/sisu/ are all clean.

Fragility caveat

This flow is fragile: it scrapes and drives Microsoft's HTML login pages, so it breaks whenever the account requires two-factor authentication, a CAPTCHA, an interrupt/consent page, or conditional-access policies, and it may break without notice if Microsoft changes those pages. The device-code (DeviceAuth/DeviceAccessToken) and authorization-code (AuthCodeURL/Exchange) flows remain preferred for interactive logins. CredentialsToken is intended only for headless, non-interactive accounts you control. This is documented on the method itself.

🤖 Generated with Claude Code


Note

High Risk
Introduces credential-based authentication that handles passwords and depends on brittle HTML scraping of Microsoft's login pages, which can break or encourage unsafe usage patterns.

Overview
Adds Config.CredentialsToken(ctx, email, password) so callers can obtain an *oauth2.Token without a browser, filling the gap versus MinecraftAuth-style credential login. The flow drives login.live.com: fetch authorize HTML, parse embedded ServerData (urlPost + PPFT), POST credentials over a cookie-jar HTTP client, read the auth code from the desktop redirect URI (oauth20_desktop.srf), then exchange it with redirect_uri pinned to that desktop URI (parallel to existing Exchange).

Failure paths surface OAuth query errors, ServerData login messages, and interrupt/2FA-style pages with explicit guidance to prefer device-code or auth-code flows. Tests cover HTML helpers and full httptest success and wrong-password paths via overridable package-level authorize/token URLs.

Reviewed by Cursor Bugbot for commit c6156cb. Bugbot is set up for automated code reviews on this repo. Configure here.

Add Config.CredentialsToken, a headless Microsoft-account username/password
login flow for the "LIVE" (login.live.com) environment. It ports RaphiMC/
MinecraftAuth's CredentialsMsaAuthService and returns an *oauth2.Token that
plugs straight into the existing SISU/Xbox Live flow.

Flow:
- GET oauth20_authorize.srf (client_id, scope, redirect_uri=oauth20_desktop.srf,
  response_type=code, response_mode=query) over a cookie-jar client.
- Scrape `var ServerData = {...}` for urlPost and the sFTTag PPFT input.
- POST login/loginfmt/passwd/PPFT to urlPost, following redirects.
- Read the authorization code from the final oauth20_desktop.srf?code=... URL
  and exchange it (redirect_uri pinned to the desktop URI).

The jar client is a shallow copy of the context client with only Jar added, so
the caller's Transport/timeout are preserved and never mutated. Pure parsing
helpers (ServerData/PPFT/code/error extraction) are factored out and unit
tested; an httptest end-to-end test covers the authorize/POST/redirect/code
path plus the token exchange, and a second covers the wrong-credentials error
path. No test makes a real network call.

Fragility caveat: this scrapes and drives Microsoft's HTML login pages, so it
breaks on 2FA, CAPTCHA, interrupt/consent, or conditional-access, and may break
without notice if Microsoft changes those pages. Device-code and auth-code
flows remain preferred for interactive logins.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Jul 1, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_8202c455-2fb6-4184-a5e1-2ec0bad5f9a2)

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 729e1a78-3a7a-4ce0-97d8-949f818e1126

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/msa-credentials

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

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