Reduce usage of std::time_t, std::chrono::system_clock::to_time_t and system_clock::from_time_t in order to get correct dates when working with a 32bit application by MarchMore · Pull Request #401 · Thalhammer/jwt-cpp

Fixing a potential "year 2038 problem" occurrence in "jwt.h".
This one seems to happen when using the library in 32-bit applications. The main problem is not the architecture itself, but the usage of "std::time_t" from "" instead of chrono-only utils in the "jwt-cpp" library.

I've added an example here in which the difference between 32-bit and 64-bit compilation can be seen clearly:

  1. Create token with "exp" of different dates
  2. Convert data to string
  3. Convert string to data
  4. See that "exp" (for year >2038) gets negative --> Which means basically "token expired"

https://godbolt.org/z/9GGqM577W

Code:

#include <chrono>
#include <iostream>

#include "jwt-cpp/jwt.h"

void analyze(std::chrono::hours hours_from_now)
{
    std::string token = jwt::create().set_expires_at(std::chrono::system_clock::now() + hours_from_now).sign(jwt::algorithm::none{});
    std::chrono::system_clock::time_point exp = jwt::decode(token).get_expires_at();

    std::cout << std::chrono::duration_cast<std::chrono::seconds>(exp.time_since_epoch()).count() << "\n";
}

int main()
{
    // Testing conversion of token with "exp" to string and back to data again
    std::cout << "Tests:\n";
    analyze(std::chrono::hours(24 * 365 * 0));  // Today
    analyze(std::chrono::hours(24 * 365 * 1));  // Today + 1 year
    analyze(std::chrono::hours(24 * 365 * 10)); // Today + 10 years
    analyze(std::chrono::hours(24 * 365 * 20)); // Today + 20 years (Potential "year 2038 problem")

    // Looking onto the problem:

    // Today + 20 years (Potential "year 2038 problem")
    const auto problematic_time_point = std::chrono::system_clock::now() + std::chrono::hours(24 * 365 * 20);

    // When converting to "std::time_t" (And so using <ctime>)
    std::cout << "\nSee problem:\n";
    long long time1 = std::chrono::system_clock::to_time_t(problematic_time_point);
    std::cout << time1 << "\n";

    // When converting to "std::chrono::duration_cast" (Using <chrono> only)
    std::cout << "\nSee solution:\n";
    long long time2 = std::chrono::duration_cast<std::chrono::seconds>(problematic_time_point.time_since_epoch()).count();
    std::cout << time2 << "\n";

    return 0;
}

Result (32-bit):

Tests:
1763856625
1795392625
2079216625
-1900390671

See problem:
-1900390671

See solution:
2394576625

Result (64-bit):

Tests:
1763856626
1795392626
2079216626
2394576626

See problem:
2394576626

See solution:
2394576626