Pumpkin-MC/Pumpkin · error · AuthError

Invalid token format

Error message

Invalid token format

What it means

AuthError::InvalidTokenFormat from the pumpkin-auth JWT module, thrown during JWT verification when the token does not have the expected three dot-separated parts (header.payload.signature). Microsoft/Mojang session JWTs must be split and each part decoded separately.

Solutions

  1. Verify the client is sending the Mojang identity JWT (three parts) from the login handshake, not an access token
  2. Split on '.' and check `parts.len() == 3` before verifying
  3. Log the first ~20 chars and part count of the received token to diagnose what the client actually sent
  4. Update the auth protocol handling if the client/server Minecraft versions differ

Example fix

// before
verify(token)?; // panics/errors when token is malformed
// after
let parts: Vec<&str> = token.split('.').collect();
if parts.len() != 3 { return Err(AuthError::InvalidTokenFormat); }
verify(token)?;
Defensive patterns

Strategy: validation

Validate before calling

let parts: Vec<&str> = token.split('.').collect();
if parts.len() != 3 || parts.iter().any(|p| p.is_empty()) { return Err("token must have 3 non-empty JWT segments"); }

Type guard

fn is_jwt_shaped(token: &str) -> bool {
    let parts: Vec<&str> = token.split('.').collect();
    parts.len() == 3 && parts.iter().all(|p| !p.is_empty())
}

Try / catch

match jwt::verify(token) {
    Err(AuthError::InvalidTokenFormat) => { log::warn!("client sent malformed token"); reject_handshake(); }
    Ok(claims) => { /* proceed */ }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling JWT verification with a token that contains fewer than 3 dot-separated segments — empty string, an OAuth access token passed instead of the identity JWT, or a corrupted/truncated token.

Common situations: Client sends the wrong token type (XBL access token vs. XSTS identity JWT); login handshake data truncated; extra whitespace or wrapping in the token field; Mojang protocol changes not handled.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of Pumpkin-MC/Pumpkin@8d4639e25a (2026-09-09). Data as JSON: /api/errors/f700b2a5dbfca8d6. Report an issue: GitHub.

Appendix: source

Thrown at crates/pumpkin-auth/src/jwt/mod.rs:33

/// Represents the claims extracted from a Minecraft Bedrock player's JWT token.
///
/// This struct contains the player's display name, UUID, and XUID.
#[derive(Debug)]
pub struct PlayerClaims {
    /// The player's display name (in-game name).
    pub display_name: String,
    /// The player's unique identifier (UUID).
    pub uuid: String,
    /// The player's Xbox User ID (XUID).
    pub xuid: String,
}

/// Represents the possible errors that can occur during JWT verification.
#[derive(Debug, Error)]
pub enum AuthError {
    /// Indicates that a JWT token has an invalid format (not enough parts).
    #[error("Invalid token format")]
    InvalidTokenFormat,
    /// Indicates that the 'x5u' (X.509 URL) header parameter is missing from a token.
    #[error("x5u not found in header")]
    MissingX5U,
    /// Indicates a failure in Base64 decoding.
    #[error("Base64 decoding failed: {0}")]
    Base64Decode(#[from] base64::DecodeError),
    /// Indicates a failure in parsing JSON data.
    #[error("JSON parse error: {0}")]
    JsonParse(#[from] serde_json::Error),
    /// Indicates a failure in building a public key from its representation.
    #[error("Public key build failed: {0}")]
    PublicKeyBuild(String),
    /// Indicates that the token was not signed by the trusted Mojang public key.
    #[error("Token not signed by trusted Mojang key")]
    MojangKeyMismatch,
    /// Indicates that the token's signature is invalid.
    #[error("Invalid signature")]

View on GitHub (pinned to 8d4639e25a)