lcobucci/jwt · error · Lcobucci\JWT\Encoding\CannotDecodeContent

Error while decoding from Base64Url, invalid base64…

Error message

Error while decoding from Base64Url, invalid base64 characters detected

What it means

This error wraps a low-level failure when decoding a Base64Url-encoded string in SodiumBase64Polyfill::base642bin. When the native sodium_base642bin() throws SodiumException (invalid base64 characters), the polyfill converts it into CannotDecodeContent::invalidBase64String(). It means the input string is not valid Base64Url data — usually it contains '+', '/', '=' or other non-URL-safe characters, or is corrupted/truncated.

Solutions

  1. Inspect the input string for illegal characters and strip/normalize '=' padding and whitespace before decoding
  2. Convert standard base64 to base64url first: strtr($value, '+/', '-_') and rtrim($value, '=')
  3. Verify the JWT is complete and was not truncated or mangled during transport/storage
  4. If you control the encoder, encode with SodiumBase64Polyfill::bin2base64($data, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING)
  5. Wrap the decode in try-catch for CannotDecodeContent and surface a clear 'invalid token encoding' message to the caller

Example fix

// before
$decoded = SodiumBase64Polyfill::base642bin($value, SODIUM_BASE64_VARIANT_URLSAFE);
// after
$value = rtrim(strtr($value, '+/', '-_'), '=');
$decoded = SodiumBase64Polyfill::base642bin($value, SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!preg_match('/^[A-Za-z0-9_-]*$/', $input)) { throw new InvalidArgumentException('Invalid base64url'); }

Type guard

function isValidBase64Url(string $s): bool { return preg_match('/^[A-Za-z0-9_-]*$/', $s) === 1; }

Try / catch

try { $decoded = SodiumBase64Polyfill::base64UrlDecode($input); } catch (Lcobucci\JWT\Encoding\CannotDecodeContent $e) { return error_400('Malformed token encoding'); }

Prevention

When it happens

Trigger: Calling base64UrlDecode() or base642bin() on a string that contains standard-Base64 characters ('+','/') instead of Base64Url ('-','_'), padding '=' characters, whitespace, or any corrupted bytes. Also raised indirectly by parser signature decoding (signatureValidationWithLocalFileKeyReferenceWillOperateWithKeyContents, initializeKey call sites) when a JWT segment is not valid Base64Url.

Common situations: Passing a regular base64-encoded token into a Base64Url decoder; copying a JWT from a source that replaced '-'/'_' with '+'/'/'; appending '=' padding that Base64Url forbids; decoding a signed payload with a truncated or tampered segment.

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 lcobucci/jwt@375813049c (2026-09-14). Data as JSON: /api/errors/fbe8fed4ae438946. Report an issue: GitHub.

Appendix: source

Thrown at src/SodiumBase64Polyfill.php:72

        return $encoded;
    }

    /**
     * @return ($encoded is non-empty-string ? non-empty-string : string)
     *
     * @throws CannotDecodeContent
     */
    public static function base642bin(string $encoded, int $variant): string
    {
        if (! function_exists('sodium_base642bin')) {
            return self::base642binFallback($encoded, $variant); // @codeCoverageIgnore
        }

        try {
            return sodium_base642bin($encoded, $variant, '');
        } catch (SodiumException) {
            throw CannotDecodeContent::invalidBase64String();
        }
    }

    /**
     * @return ($encoded is non-empty-string ? non-empty-string : string)
     *
     * @throws CannotDecodeContent
     */
    public static function base642binFallback(string $encoded, int $variant): string
    {
        if (
            $variant === self::SODIUM_BASE64_VARIANT_URLSAFE
            || $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
        ) {
            $encoded = strtr($encoded, '-_', '+/');
        }

        $decoded = base64_decode($encoded, true);

View on GitHub (pinned to 375813049c)