PaperMC / PaperMC/Velocity

[Feature Request]Proposal: Add a stable connection identifier accessible across all login-phase events

Open
#1,839 2 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

Requested Feature

Add a unique, stable connection identifier to the InboundConnection interface so plugins can reliably correlate the same TCP connection across PreLoginEvent, GameProfileRequestEvent, and LoginEvent.

Something like:

public interface InboundConnection {
    // existing methods...

    /**
     * Returns a unique identifier for this connection, stable for the
     * entire lifetime of the connection.
     */
    UUID getConnectionId();  // or long
}

The identifier should be:

  • Generated once per TCP connection (in HandshakeSessionHandler / InitialInboundConnection constructor)
  • Available across all login-phase events: PreLoginEvent, GameProfileRequestEvent, and ideally also from LoginEvent (via ConnectedPlayer or a similar accessor)
  • Consistent even when the InboundConnection wrapper object changes internally
Why is this needed?

event.getConnection() returns a LoginInboundConnection that—while the same instance in normal code paths—can become a different wrapper in certain scenarios (possibly related to the 1.20.2+ login acknowledgement / config phase). This breaks plugin code that relies on object identity:

PreLoginEvent:          conn.hashCode() = 0x43BED29E  ← wrapper A
GameProfileRequestEvent: conn.hashCode() = 0x7EB37DA9  ← wrapper B (different!)

To give some context: we are developing an offline-mode authentication plugin that also supports premium (Mojang-authenticated) players. When a premium player logs in, we need to replace their Mojang UUID with an offline-mode UUID in GameProfileRequestEvent so the backend servers always see the same UUID regardless of the player's online/offline status. This requires tracking the same connection across PreLoginEvent (where we detect a premium login request), GameProfileRequestEvent (where we replace the UUID and playername), and LoginEvent (where we persist the premium UUID mapping). Without a stable connection identifier, we cannot reliably associate these three events.

I believe this feature would be useful for any plugin that needs to track state through the login pipeline—not just authentication plugins, but also anti-bot, name-restriction, or connection-rate-limiting plugins.

Alternative Solutions

Currently we use a triple-index fallback (connection → UUID → name), which works but is fragile:

  1. Object reference identity (== comparison on InboundConnection): works in theory but fails when the wrapper object changes internally during the login pipeline transition.
  2. Reflection on LoginInboundConnection.delegate: reaches the underlying MinecraftConnection.getChannel().id(), but depends on private field names that may change between versions.
  3. getRemoteAddress() + getProtocolVersion() composite key: not reliable because port numbers can change on rapid reconnect.
  4. Name-based fallback: fragile if the claimed name differs from the resolved name (online mode Mojang rename).

A dedicated getConnectionId() on InboundConnection is the cleanest solution.

Additional Information

I am a teenager from China communicating through a translator, so there may be unclear expressions—please excuse me. If you find this proposal feasible, I would be happy to help implement it with some guidance.

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 by tracing InboundConnection implementations, especially HandshakeSessionHandler and the InitialInboundConnection constructor, then follow how PreLoginEvent, GameProfileRequestEvent, and LoginEvent obtain their connection data. Define how one identifier remains stable when wrapper objects change and determine how LoginEvent should expose it. Done means the identifier is generated once per TCP connection and is consistently accessible across the login-phase events.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend-api-design
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.