Skip to main content

Async Python client for Microsoft → Minecraft authentication and the Mojang REST APIs (typed, httpx-based)

Project description

mcapi-auth

CI coverage python license

⚠️ Project status: alpha. API surface may change without warning until 1.0.

Async, typed Python library that covers both halves of "talking to the Mojang/Microsoft Minecraft stack":

  • Auth (mcapi_auth.auth) — the 5-stage Microsoft → Xbox → Mojang handshake to turn a Microsoft account into a Minecraft access token + UUID + username, plus the related helpers (auth-code/PKCE, browser redirect listener, cookie-based silent flows, entitlements, joinServer, refresh-token storage, JWT decode).
  • API (mcapi_auth.api) — the public + authed Mojang/Minecraft REST surface: UUID lookups, public profile + texture decode, blocked servers, authed profile / skin / cape / name endpoints, piston-meta version manifest.

This is the merger of the previously separate mcauth and mcapi packages; see CHANGELOG.md for the migration notes.

Requires Python 3.14+. Runtime dependencies: httpx, pydantic >= 2, whenever >= 0.10.

Installation

pip install mcapi-auth                # once published
# or, from source:
git clone git@github.com:clawdbot-silly-waddle/mcapi-auth.git
cd mcapi-auth
uv sync

Quickstart — auth + a couple of API calls

import asyncio
from mcapi_auth import login_device_code_v1, get_own_profile, get_uuid_by_name

async def main() -> None:
    session = await login_device_code_v1()       # Microsoft → Minecraft token
    # Pass ``storage=FileTokenStorage()`` to persist the refresh token
    # across runs — by default tokens live only in memory.
    print(session.username, session.uuid_dashed)

    profile = await get_own_profile(session)      # accepts session or raw str
    print(profile.skins, profile.capes)

    other = await get_uuid_by_name("Notch")       # public lookup, no auth
    print(other)

asyncio.run(main())

First run: a URL + 8-character code is printed; visit, paste, sign in. To persist the refresh token across runs (so subsequent launches skip the interactive step), pass storage=FileTokenStorage() to login_device_code_v1(). The default NullTokenStorage keeps state in memory only.

Synchronous usage

If you can't or don't want to write async code (one-off scripts, Django/Flask views), use the sync facade — every public async function is exposed as a blocking wrapper that runs in a fresh event loop:

from mcapi_auth import sync as mcapi

session = mcapi.login()                       # blocks until done
profile = mcapi.get_own_profile(token=session.access_token)
print(profile.name, profile.id)

Caveats:

  • Each call spins up a fresh asyncio.run(...) loop — fine for ad-hoc scripts, not great if you want connection pooling across many calls.
  • Do not call mcapi_auth.sync.* from inside a running asyncio loop. It will raise — use the async API directly in that case.
  • The full async surface (~73 functions including login, refresh_*, get_*, change_*, fetch_*, is_*, accept_*, start_*) is available. from mcapi_auth import sync; dir(sync) lists them.

Package layout

mcapi_auth/
├── auth/      # token-chain stages, cookie flows, storage, JWT decode
├── api/       # public lookups + authed profile/skin/cape/name + piston-meta
└── exceptions # unified McApiAuthError tree (McAuthError + McApiError)

Everyday names are re-exported from the top level so most code can do from mcapi_auth import X. Reach into the subpackages for niche helpers (e.g. from mcapi_auth.auth.auth_code import ... for the PKCE flow).

Browser-driven login (no codes to type)

If your app can open a browser, login_browser_v2() is friendlier: it spins up a localhost listener, opens the MSA authorize URL, catches the redirect, and validates CSRF state — all stdlib, no extra deps.

from mcapi_auth import login_browser_v2

session = await login_browser_v2(prompt="select_account")

See examples/browser_login.py for a runnable script.

Custom prompt display

from mcapi_auth import DeviceCodePrompt, login_device_code_v1

async def show(prompt: DeviceCodePrompt) -> None:
    await channel.send(
        f"Sign in here within {prompt.expires_in}s: {prompt.verification_uri}\n"
        f"Code: `{prompt.user_code}`"
    )

session = await login_device_code_v1(on_device_code=show)

Custom token storage

from mcapi_auth import TokenStorage, login_device_code_v1

class MemoryStorage(TokenStorage):
    def __init__(self) -> None:
        self._token: str | None = None
    async def load(self) -> str | None: return self._token
    async def save(self, refresh_token: str) -> None: self._token = refresh_token
    async def clear(self) -> None: self._token = None

session = await login_device_code_v1(storage=MemoryStorage())

The default storage (FileTokenStorage) writes JSON to $XDG_STATE_HOME/mcapi_auth/refresh_token.json (falling back to ~/.local/state/mcapi_auth/refresh_token.json) with 0600 permissions and atomic replace on save.

Public API endpoints

The mcapi_auth.api half wraps Mojang's public + authed REST surface:

from mcapi_auth import (
    # public — no auth
    get_uuid_by_name, get_uuids_by_names, get_profile_by_uuid,
    extract_textures, fetch_blocked_servers, is_server_blocked,
    fetch_version_manifest,
    # authed — pass a session or a raw access-token str
    get_own_profile, change_skin_from_url, change_skin_from_file,
    reset_skin, change_cape, disable_cape,
    check_name_availability, change_name, get_name_change_eligibility,
)

uuid = await get_uuid_by_name("Notch")
profile = await get_profile_by_uuid(uuid.id)
decoded = extract_textures(profile)            # skin URL, cape URL, slim/classic
print(decoded.skin.url, decoded.skin.model)

manifest = await fetch_version_manifest()
print(manifest.latest_release, manifest.latest_snapshot)

Every authed endpoint accepts either a raw access-token string or any object exposing an .access_token attribute — which is exactly what MinecraftSession provides, so you can pass the result of login_device_code_v1() directly.

Typed errors

Two parallel hierarchies live under a single root:

McApiAuthError
├── McAuthError                         (auth-chain failures)
│   ├── MSAAuthError
│   │   ├── MSAFlowError
│   │   ├── DeviceCodeExpiredError
│   │   └── AuthorizationDeclinedError
│   ├── XboxAuthError
│   │   └── XSTSError                   (carries XErr code)
│   │       ├── NoXboxAccountError      # 2148916233
│   │       ├── RegionBlockedError      # 2148916235
│   │       ├── VerifyAgeRequiredError  # 2148916236
│   │       ├── AdultVerificationRequiredError  # 2148916237
│   │       └── ChildAccountError       # 2148916238 (needs Family Pack)
│   └── MinecraftAuthError
│       └── MinecraftProfileNotFoundError
└── McApiError                          (REST API failures)
    ├── HttpError                       (status_code, body, url)
    ├── NotFoundError
    ├── BadRequestError                 # 400
    ├── UnauthorizedError               # 401
    ├── ForbiddenError                  # 403
    ├── RateLimitedError                # 429, carries retry_after
    ├── InvalidProfileError
    ├── NameTakenError
    ├── NameNotAllowedError
    └── TooManyNamesError

MCAuthError was an alias of McAuthError in 0.3.x; it was removed in 0.4. Network-level failures (httpx.RequestError, TimeoutError) propagate unchanged — those aren't this library's domain.

Reusing an httpx.AsyncClient

Every public function accepts an optional http_client= so callers can plug in custom timeouts, proxies, transport mocks, retry transports, caching transports, etc:

async with httpx.AsyncClient(timeout=15.0, proxy="http://...") as client:
    session = await login_device_code_v1(http_client=client)
    profile = await get_own_profile(session, http_client=client)

Retries and HTTP caching

mcapi-auth doesn't bake in a retry or caching layer — they're httpx-level concerns, so attach them to the client you pass in.

  • httpx-retries for exponential-backoff retries:

    from httpx_retries import Retry, RetryTransport
    
    retry = Retry(total=5, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504])
    async with httpx.AsyncClient(transport=RetryTransport(retry=retry)) as client:
        ...
    

    Be conservative with retry counts on the MSA / XSTS / Mojang token endpoints — they're rate-limit-sensitive. Public lookup endpoints (api.mojang.com) are friendlier; respect Retry-After on 429.

  • hishel for RFC 9111 HTTP caching. Mojang's public profile / piston-meta / blocked-servers endpoints return Cache-Control headers; wrapping the client in a hishel cache transport gives you transparent revalidation for free. Token-mint endpoints (login.live.com, XBL, XSTS, loginWithXbox) shouldn't be cached — they correctly emit no-store, so they pass through.

Customising the default User-Agent

When you don't pass http_client=, the library builds a fallback client that sends User-Agent: mcapi-auth/<version>. Override it process-wide with:

from mcapi_auth import set_default_user_agent, get_default_user_agent

set_default_user_agent("my-app/1.2.3 (+https://example.org/contact)")
print(get_default_user_agent())  # "my-app/1.2.3 (…)"

Caller-supplied clients are never mutated — if you pass your own httpx.AsyncClient, its headers stay exactly as you configured them. Blank values are rejected with ValueError.

Cookie-based bulk auth

For unattended automation against accounts you own, mcapi_auth.auth.cookies ports the three flows that work from a captured Microsoft session without typing a password:

from mcapi_auth import (
    login_with_cookies_msa_v1,
    login_with_cookies_sisu,
    login_with_cookies_msa_v2_loopback,
    CookieAuthError,
    BrowserCookie,
)

# Flow 1 — Live-Connect "Java public client": returns MSA access+refresh
tokens = await login_with_cookies_msa_v1("MSPAuth=...; MSPProf=...")

# Flow 2 — SISU (Xbox SSO): returns XBL/XSTS tokens (no refresh available)
sisu = await login_with_cookies_sisu("MSPAuth=...; MSPProf=...")

# Flow 3 — Prism Launcher (Azure-AD consumers): accepts structured cookies
tokens = await login_with_cookies_msa_v2_loopback([
    BrowserCookie(name="MSPAuth", value="...", domain=".live.com"),
    BrowserCookie(name="MSPProf", value="...", domain=".live.com"),
])

Cookie acquisition is intentionally out of scope — bring your own Selenium / nodriver / playwright session. See examples/cookie_login.py for the "try MSA-v1, fall back to SISU on CookieAuthError" pattern.

⚠️ These primitives let you act as an account using its session cookies. Only use them on accounts you own or have explicit permission to automate.

Beyond login_device_code_v1()

A few additional auth-side helpers:

  • mcapi_auth.auth.auth_code — authorization-code + PKCE entry point for desktop apps that prefer a localhost redirect over device-code.
  • mcapi_auth.decode_minecraft_access_token(token) — decode the MC JWT offline to read exp / username / UUID from the embedded pfd claim.
  • mcapi_auth.fetch_entitlements(access_token)/entitlements/mcstorehas_java / has_bedrock / has_game_pass. Distinguishes "doesn't own MC" from "owns Bedrock only" (/minecraft/profile 404s in both).
  • mcapi_auth.join_server(...)sessionserver.mojang.com/session/minecraft/join, for proving profile ownership during a third-party-server handshake.

Long-running apps — AuthChain + Holder

For apps that hold a single account open for hours/days, mcapi_auth.AuthChain wraps the full MSA → XBL → XSTS → Minecraft token chain with per-stage lazy refresh and listeners. Each stage is a Holder[T] that knows how to refresh itself when expired; downstream holders are invalidated automatically on MSA rotation.

from mcapi_auth import AuthChain, MsaApplicationConfig

# Default: v1 device-code flow with the official MC launcher client_id.
chain = await AuthChain.login()

# For v2 / Azure-AD instead:
# chain = await AuthChain.login(
#     flow="device_code_v2", app=MsaApplicationConfig.from_known("prism")
# )

# Persist on every rotation:
chain.on_change(lambda stage, _old, _new: state.save(chain.dump_json()))

while running:
    mc = await chain.get_minecraft_token()    # refreshes if expired
    await do_stuff(mc.access_token)

Restoring across restarts retains XBL+XSTS so you don't re-derive the chain on cold start:

chain = AuthChain.load_json(state.load(), app=MsaApplicationConfig.v1_launcher())
mc = await chain.get_minecraft_token()   # uses cached values when fresh

MsaApplicationConfig bundles (client_id, scope, authorize_url, token_url, device_code_url, redirect_uri, xbl_use_d_prefix, is_v1) so the same config can be threaded through every helper:

  • MsaApplicationConfig.v2(client_id=...) — modern consumers endpoint.
  • MsaApplicationConfig.v1_launcher(client_id=...) — legacy Live-Connect endpoint, MBI_SSL scope, raw RPS ticket.
  • MsaApplicationConfig.from_known(alias) — resolve an alias ("prism", "java", "liquidlauncher", "bedrock-android", …) into the correctly-shaped v1 or v2 config, with the known redirect override applied.

Realms (Java edition)

from mcapi_auth import (
    accept_realms_tos,
    fetch_realms_join_info,
    fetch_realms_worlds,
    is_realms_tos_agreed,
)

if not await is_realms_tos_agreed(session):
    await accept_realms_tos(session)

for world in await fetch_realms_worlds(session):
    print(world.world_id, world.name, world.owner_username)

info = await fetch_realms_join_info(session, world.world_id)
print(info.host, info.port)

All Realms calls accept any MinecraftSession-like object (anything exposing access_token + uuid + username), including an AuthChain.to_session() result. The version= cookie defaults to mcapi_auth.DEFAULT_REALMS_GAME_VERSION (currently "1.21.4"); pass game_version="..." to override.

Bedrock realms are not implemented (Bedrock uses a different API and different XSTS relying party).

Proxying a Minecraft client — join_server + server-id hash

For implementing the client side of online-mode authentication (e.g. a Minecraft proxy, a custom auth gateway, or an axochat-style service):

from mcapi_auth import (
    compute_server_id_hash,
    join_server,
    join_server_with_session,
)

# Low-level: you already have a server-id hash
await join_server(session, server_id="abc123...")

# High-level: hand it the raw fields from the Encryption Request packet
await join_server_with_session(
    session,
    server_id_str=encryption_request.server_id,     # ASCII, ≤20 chars, often ""
    shared_secret=client_aes_key,                   # 16-byte AES key the client generated
    public_key_der=encryption_request.public_key,   # X.509 SubjectPublicKeyInfo blob
)

compute_server_id_hash() is exposed separately for tests / inspection. It implements the Notchian signed-hex SHA-1 (digest interpreted as a 160-bit two's-complement integer, hex-formatted with no leading zeros).

Debugging a chain — describe_chain / chain_state_summary

from mcapi_auth import describe_chain, chain_state_summary, describe_minecraft_token

print(describe_chain(chain))
# AuthChain  client_id=00000000402b5328  v1=True
#   msa        ✓  59min                (EwAIA...(982 chars))
#   xbl        ·  —
#   xsts       ·  —
#   minecraft  ✓  23.9hr               (eyJhbG...(842 chars))
#   profile    ✓  —                    (Notch <069a79f444e9...>)

# Machine-readable form for logs / metrics:
for row in chain_state_summary(chain):
    log.info("stage", **row.to_dict())

# Peek at the JWT claims of a Minecraft access token:
print(describe_minecraft_token(chain.minecraft_holder.get_cached().access_token))

All helpers are read-only, redact token bodies, and never make network calls.

Multiple accounts — AccountManager

For programs juggling several accounts (chat bridges, alt managers, multi-account servers), AccountManager stores chains as one JSON file per account under ~/.local/state/mcapi_auth/accounts/:

from mcapi_auth import AccountManager, AuthChain, MsaApplicationConfig

mgr = AccountManager()  # or AccountManager(Path("/var/lib/mybot/accounts"))

# After login, save the chain under a label (the username is a natural choice):
chain = await AuthChain.login(app=MsaApplicationConfig.v2(), prompt=...)
profile = await chain.get_profile()
await mgr.save(profile.username, chain)

# Next run:
print(mgr.list_labels())          # ['Notch', 'jeb_', ...]
chain = await mgr.load("Notch")
mc = await chain.get_minecraft_token()

# Auto-persist on token rotation:
chain.on_change(mgr.make_listener_for("Notch", chain))

# Or restore everything at once:
chains = await mgr.load_all()      # dict[str, AuthChain]

Labels must match [A-Za-z0-9._-] and start with an alphanumeric (rejects .., /, leading dots). Files are written atomically with 0600 permissions. The default directory honours XDG_STATE_HOME.

Player chat-signing certificates (1.19+)

Minecraft 1.19 introduced signed chat (and chat reporting in 1.19.1+); the client must fetch a Mojang-signed RSA key-pair from /player/certificates and sign outbound messages with it.

from mcapi_auth import fetch_player_certificates

certs = await fetch_player_certificates(session)
print(certs.expires_at, certs.refreshed_after)
public_der = certs.key_pair.public_key_der()        # raw DER bytes
mojang_sig = certs.public_key_signature_v2_bytes    # base64-decoded

MinecraftKeyPair.public_key / private_key are PEM strings; .public_key_der() / .private_key_der() strip the PEM armor and base64-decode for you. No cryptography dependency — load the keys with your preferred crypto library if you need to sign.

PlayFab login (Bedrock telemetry)

Minecraft: Bedrock Edition logs into PlayFab in addition to Xbox Live, using an XSTS token. Once authenticated you get a PlayFab entity token (short-lived JWT used by the title service), a stable PlayFab account id, and a long-lived session ticket.

from mcapi_auth import (
    BEDROCK_PLAYFAB_TITLE_ID,
    playfab_get_entity_token,
    playfab_login_with_xbox,
)

# `xsts` here is an mcapi_auth.XSTSToken — for PlayFab you usually
# want an XSTS issued against rp `http://playfab.xboxlive.com/`,
# which differs from the Minecraft RP. Get it however you like; this
# function only consumes the token.
pf = await playfab_login_with_xbox(xsts, title_id=BEDROCK_PLAYFAB_TITLE_ID)
print(pf.play_fab_id, pf.session_ticket, pf.entity_token.expires_at)

# Refresh just the entity token later, no XSTS round-trip needed:
new_entity = await playfab_get_entity_token(pf.entity_token)

This module covers the PlayFab piece only — see the Bedrock section below for the rest of the client chain.

Bedrock Edition client chain

Optional, requires the [bedrock] extra (which pulls in cryptography>=43 for the ES384 keypair):

pip install mcapi-auth[bedrock]

Once an XSTS token scoped to Bedrock's relying party (https://multiplayer.minecraft.net/) and a PlayFab session ticket are in hand, you can run the rest of the chain:

from mcapi_auth.api.bedrock import (
    generate_bedrock_session_keypair,
    minecraft_authenticate,
    start_minecraft_session,
    start_minecraft_multiplayer_session,
)
from uuid import uuid4

key_pair = generate_bedrock_session_keypair()        # ES384 / P-384
chain = await minecraft_authenticate(bedrock_xsts, key_pair)
print(chain.xuid, chain.display_name, chain.expires_at)

session = await start_minecraft_session(
    pf.session_ticket,
    game_version="1.21.50",
    device_id=uuid4(),
)
mp = await start_minecraft_multiplayer_session(session, key_pair)
print(mp.xuid, mp.uuid, mp.token)

The ES384 keypair should be persisted across launches — Mojang binds it to the player's account in the identityJwt. Use BedrockKeyPair.to_pem() / BedrockKeyPair.from_pem() for storage.

Note: mcapi_auth's built-in authenticate_xsts() is scoped to the Java relying party. For a Bedrock-scoped XSTS use the Sisu flow in mcapi_auth.auth.xbox_device (added in 0.12.0) — it returns a UserToken, TitleToken, and an XSTSToken in one call, all bound to a persistent device keypair. See examples/bedrock_minimal.py.

Sisu flow / device-token authentication

For Bedrock and other Microsoft title client ids, the plain user.auth.xboxlive.com + xsts.auth.xboxlive.com chain is insufficient — you need a TitleToken as well, which only the Sisu endpoint mints. The mcapi_auth.auth.xbox_device module wraps it:

from mcapi_auth import BEDROCK_WIN32_CLIENT_ID
from mcapi_auth.auth.xbox_device import (
    XBL_XSTS_BEDROCK_RELYING_PARTY,
    XblDeviceKeyPair,
    authenticate_xbl_device,
    sisu_authorize,
)
from uuid import uuid4

# Persist these across launches; Xbox treats them as a device identity.
device_kp = XblDeviceKeyPair.generate()
device_id = uuid4()

device_token = await authenticate_xbl_device(device_kp, device_id=device_id)

sisu = await sisu_authorize(
    msa.access_token,
    device_token,
    device_kp,
    client_id=BEDROCK_WIN32_CLIENT_ID,
    relying_party=XBL_XSTS_BEDROCK_RELYING_PARTY,
)
print(sisu.xsts_token.token, sisu.user_token.userhash, sisu.title_token.title_id)

The returned sisu.xsts_token is shape-compatible with mcapi_auth.XSTSToken (same .token / .userhash attributes) and can be passed straight to minecraft_authenticate, playfab_login_with_xbox, or any of the other XSTS-consuming helpers. Requires the [bedrock] extra (for cryptography).

BedrockAuthManager: full chain with lazy refresh

For long-running clients, BedrockAuthManager (added in 0.13.0) is the Bedrock equivalent of AuthChain — it owns the stable Xbox identity (device keypair + UUID + ES384 client keypair) and every downstream token (MSA, DeviceToken, the two Sisu legs, PlayFab, certificate chain, franchise session, multiplayer token), each in a Holder that refreshes on demand:

from mcapi_auth.auth.bedrock_chain import BedrockAuthManager

mgr = await BedrockAuthManager.login()
mgr.on_change(lambda *_: state.save(mgr.dump_json()))

while running:
    mp = await mgr.get_multiplayer_token()   # auto-refreshes
    await join_server(mp.token)

# later, in another process:
mgr = BedrockAuthManager.load_json(state.load())
cert = await mgr.get_certificate_chain()

BedrockAuthManager.login() accepts both v1 and v2 client_ids. By default it builds a MsaApplicationConfig.v1_launcher(client_id= bedrock_client_id) and threads the matching device_code_url / token_url / scope through the MSA layer — so every Bedrock client_id (Win32, Android, iOS, Nintendo, PlayStation), which is only registered against Microsoft's legacy login.live.com/oauth20_*.srf endpoints, works without an explicit config.

Bootstrap shortcut: the Bedrock-Win32 client_id is registered against a custom-protocol redirect that browsers can't follow, so for a first-time browser-driven bootstrap you can drive the MSA leg with the Java launcher's client_id (MINECRAFT_LAUNCHER_V1_CLIENT_ID) — XBL entitlement is keyed off the resulting Xbox profile, not off the MSA client_id — and pass bedrock_client_id=BEDROCK_WIN32_CLIENT_ID to BedrockAuthManager.from_msa(...) so the rest of the chain still targets the Bedrock relying party. The refreshed snapshot stores the Bedrock client_id and uses it on subsequent refreshes.

Persistence keeps the device keypair + UUID stable across runs (Xbox remembers them as a single device identity), and only the stages whose inputs actually changed are invalidated on refresh — e.g. an MSA rotation re-runs the Sisu legs but keeps the DeviceToken.

More examples

See examples/ for runnable scripts covering each entry point: device-code, browser-driven, refresh-token reuse, cookie-based bulk auth, custom storage, manual auth-code integration, entitlements, joinServer, and offline JWT decode.

Development

uv sync
uv run pytest
uv run ruff check .
uv run basedpyright

Why not msal?

Microsoft's official library is ~7 MB of code that mostly handles enterprise tenants we don't need. The device-code flow is ~50 lines hand-rolled with httpx — see src/mcapi_auth/auth/msa.py.

Client-ID disclaimer

By default we use the public Minecraft Launcher client_id (00000000-402b-4cd3-a82b-c45ab2f1d3f7) that every open-source launcher relies on. Microsoft has tolerated this for ~5 years; if they ever revoke it, every Minecraft launcher on Earth breaks the same day. Pass a different client_id= to login_device_code_v1() if you have your own MSA app registration.

Known client_id catalog

mcapi_auth.KNOWN_CLIENT_IDS maps friendly aliases to well-known Microsoft client_ids used across the Minecraft ecosystem. v1 (16-hex, no dashes) IDs work against login.live.com/oauth20_*.srf with the MBI_SSL scope; v2 (Azure-AD GUID) IDs work against login.microsoftonline.com/consumers/oauth2/v2.0/* with XboxLive.signin offline_access.

The matrix below is what each client_id actually accepts as a redirect_uri, as derived from probing every entry end-to-end against the v1 and v2 authorize endpoints. Use the listed flow:

alias type accepted redirect_uri(s) flow
java v1 OOB only (oauth20_desktop.srf) login_browser_v1
bedrock-android v1 OOB only login_browser_v1
bedrock-ios v1 OOB only login_browser_v1
bedrock-nintendo v1 OOB only login_browser_v1
bedrock-playstation v1 OOB only login_browser_v1
bedrock-win32 v1 broken upstream for OOB. Use java / MINECRAFT_LAUNCHER_V1_CLIENT_ID for the MSA leg and bedrock_client_id=BEDROCK_WIN32_CLIENT_ID on BedrockAuthManager — XBL entitlement keys off the resulting Xbox profile, not the MSA client_id. (MSA via java)
xbox-app-ios v1 OOB only login_browser_v1
xbox-gamepass-ios v1 OOB only login_browser_v1
prism (default) v2 http://{127.0.0.1,localhost}:*/ (root path) login_browser_v2 or login_device_code_v2
liquidlauncher/liquidbounce v2 http://localhost:*/login login_browser_v2 or login_device_code_v2
edu v2 none — no loopback registered login_device_code_v1 only
office365 v2 none — no loopback registered login_device_code_v1 only

Helpers:

  • is_v1_client_id(client_id) — decide between v1/v2 endpoint families.
  • resolve_client_id(name_or_id) — alias → client_id lookup.
  • resolve_browser_redirect(client_id) — returns (bind_host, redirect_path) for clients with a known registered loopback URI (currently prism, liquidlauncher); None otherwise.
  • is_browser_unsupported(client_id)True if login_browser_v2 (v2 loopback) cannot succeed for this client_id: every v1 ID (rejected by the v2 endpoint as AADSTS70001) plus every v2 ID without a loopback URL registered (edu, office365).

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcapi_auth-0.19.3.tar.gz (257.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcapi_auth-0.19.3-py3-none-any.whl (130.7 kB view details)

Uploaded Python 3

File details

Details for the file mcapi_auth-0.19.3.tar.gz.

File metadata

  • Download URL: mcapi_auth-0.19.3.tar.gz
  • Upload date:
  • Size: 257.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for mcapi_auth-0.19.3.tar.gz
Algorithm Hash digest
SHA256 d66715668dfda5773abe41722bca839353092cfdb2755e4ef242eccc4847285d
MD5 73fe0fdb51e4beca174c2f83cabdc5a8
BLAKE2b-256 93173e80613505c46939f2c8e389ba22b778c691ec81396d11279ecf77db45f1

See more details on using hashes here.

File details

Details for the file mcapi_auth-0.19.3-py3-none-any.whl.

File metadata

  • Download URL: mcapi_auth-0.19.3-py3-none-any.whl
  • Upload date:
  • Size: 130.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for mcapi_auth-0.19.3-py3-none-any.whl
Algorithm Hash digest
SHA256 7d28b684f2df9d8b914738fb08e9e0107c6b54506692a20e8c744609d96a2870
MD5 9439806a03b5ec801e55328930fb9198
BLAKE2b-256 4ca6d76357209585a1c589ee1c149dfa70d3d0be8ed2b67d0ba17e75ce978a37

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page