PaperMC / PaperMC/Velocity

Let plugins control the client-facing onlineMode flag (26.2+) when they rewrite the profile UUID

Open
#1,875 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type: feature
Dominant language
Java
Stars
2.3k
Forks
960
Avg merge
5d 10h
Merged PRs (30d)
2

Description

Since 26.2 the game join packet carries an onlineMode boolean, and Velocity overwrites whatever the backend sent with player.isOnlineMode() (TransitionSessionHandler, d7ad0522). That mirrors what the client used to derive from Connection#isEncrypted, so it's a sensible default — but the client-facing "online mode" signal is now the proxy's decision, and plugins have no say in it.

Where this bites: premium auto-login plugins force online-mode in PreLoginEvent to verify the Mojang session, then rewrite the UUID back to the offline v3 one in GameProfileRequestEvent so existing world data keeps working. The client is now told it's on an online-mode server while its UUID doesn't belong to the session it authenticated with, so everything that goes through the Mojang session (profile key pair, tab heads, social block lists, mods reading connection.onlineMode()) resolves "me" to a UUID that matches nothing in the world. Report with pets, Chat Heads and Simple Voice Chat breaking while server-side data stays consistent: AuthMe/AuthMeReloaded#3126; the same account logged in as plain offline works fine.

Before 26.2 the mismatch was keyed on encryption itself and nothing proxy-side could change it; now the client trusts the flag, so this is fixable — there's just no way to set it. The only workaround is to skip forceOnlineMode() and redo the encryption / hasJoined handshake via PacketEvents so the login continues as offline: Java AES/CFB8 instead of native ciphers, custom handlers in Velocity's pipeline, and a second copy of login-state handling to maintain.

Two possible shapes, from small to proper:

  1. Make the client-facing flag controllable, without changing anything by default:

    • (a) Plugin API — e.g. GameProfileRequestEvent#setClientOnlineMode(boolean), distinct from isOnlineMode(), which keeps meaning "authenticated with Mojang". This is what a plugin like AuthMe would call.

    • (b) Opt-in config flag that sends false whenever the final profile id differs from the authenticated one. Velocity already treats that mismatch as broken ("UUID for Player mismatches! Chat/Commands signatures will not work correctly" in AuthSessionHandler), and it also happens with player-info-forwarding-mode = none — the case #1806 works around on the chat-session side. This covers setups without a plugin in the loop.

  2. A PreLogin result that verifies the Mojang session but keeps the offline identity — say verifyOnlineMode(). Same encryption request and hasJoined as forceOnlineMode(), but afterwards the connection continues down the normal offline path: offline v3 profile from the username, isOnlineMode() false, offline UUID forwarded, false in the join packet. The verified Mojang profile is handed to plugins separately, e.g. GameProfileRequestEvent#getVerifiedProfile(), to check against a database, forward in a signed message, or copy skin properties from.

    For AuthMe this replaces forceOnlineMode() + setGameProfile(profile.withId(offlineUuid)) with one result and one getter, and nothing is left to keep consistent by hand: the UUID rewrite goes away because Velocity built the offline profile itself, there's no flag to override because isOnlineMode() is genuinely false, and the verified profile comes from the API instead of getOriginalProfile(). It's what such plugins emulate today with PacketEvents, done natively.

Option 1a alone would already fix the reported breakage without any plugin touching the pipeline. Happy to help with a PR for either.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with TransitionSessionHandler and AuthSessionHandler to trace how the client-facing onlineMode flag and profile UUID are selected. Then review PreLoginEvent, GameProfileRequestEvent, and forceOnlineMode() to compare the proposed API and verified-profile approaches. Done means an agreed design lets plugins preserve the authenticated profile separately from the client-facing identity without breaking existing defaults.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
authentication, backend, backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.