#define JWT_DISABLE_PICOJSON // Make sure JWT compiles with this flag #include #include "jwt-cpp/jwt.h" #include "nlohmann/json.hpp" struct nlohmann_traits { using json = nlohmann::json; using value_type = json; using object_type = json::object_t; using array_type = json::array_t; using string_type = std::string; // current limitation of traits implementation using number_type = json::number_float_t; using integer_type = json::number_integer_t; using boolean_type = json::boolean_t; static jwt::json::type get_type(const json &val) { using jwt::json::type; if (val.type() == json::value_t::boolean) return type::boolean; else if (val.type() == json::value_t::number_integer) return type::integer; else if (val.type() == json::value_t::number_unsigned) // nlohmann internally tracks two types of integers return type::integer; else if (val.type() == json::value_t::number_float) return type::number; else if (val.type() == json::value_t::string) return type::string; else if (val.type() == json::value_t::array) return type::array; else if (val.type() == json::value_t::object) return type::object; else throw std::logic_error("invalid type"); } static json::object_t as_object(const json &val) { if (val.type() != json::value_t::object) throw std::bad_cast(); return val.get(); } static std::string as_string(const json &val) { if (val.type() != json::value_t::string) throw std::bad_cast(); return val.get(); } static json::array_t as_array(const json &val) { if (val.type() != json::value_t::array) throw std::bad_cast(); return val.get(); } static int64_t as_int(const json &val) { switch(val.type()) { case json::value_t::number_integer: case json::value_t::number_unsigned: return val.get(); default: throw std::bad_cast(); } } static bool as_bool(const json &val) { if (val.type() != json::value_t::boolean) throw std::bad_cast(); return val.get(); } static double as_number(const json &val) { if (val.type() != json::value_t::number_float) throw std::bad_cast(); return val.get(); } static bool parse(json &val, std::string str) { val = json::parse(str.begin(), str.end()); return true; } static std::string serialize(const json &val) { return val.dump(); } }; TEST(NlohmannTest, BasicClaims) { using nlohmann_claim = jwt::basic_claim; const auto string = nlohmann_claim(std::string("string")); const auto array = nlohmann_claim(std::set{"string", "string"}); const auto integer = nlohmann_claim(159816816); } TEST(NlohmannTest, AudienceAsString) { std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0In0." "WZnM3SIiSRHsbO3O7Z2bmIzTJ4EC32HRBKfLznHhrh4"; auto decoded = jwt::decode(token); ASSERT_TRUE(decoded.has_algorithm()); ASSERT_TRUE(decoded.has_type()); ASSERT_FALSE(decoded.has_content_type()); ASSERT_FALSE(decoded.has_key_id()); ASSERT_FALSE(decoded.has_issuer()); ASSERT_FALSE(decoded.has_subject()); ASSERT_TRUE(decoded.has_audience()); ASSERT_FALSE(decoded.has_expires_at()); ASSERT_FALSE(decoded.has_not_before()); ASSERT_FALSE(decoded.has_issued_at()); ASSERT_FALSE(decoded.has_id()); ASSERT_EQ("HS256", decoded.get_algorithm()); ASSERT_EQ("JWT", decoded.get_type()); auto aud = decoded.get_audience(); ASSERT_EQ(1, aud.size()); ASSERT_EQ("test", *aud.begin()); } TEST(NlohmannTest, SetArray) { std::vector vect = { 100, 20, 10 }; auto token = jwt::create() .set_payload_claim("test", jwt::basic_claim(vect.begin(), vect.end())) .sign(jwt::algorithm::none{}); ASSERT_EQ(token, "eyJhbGciOiJub25lIn0.eyJ0ZXN0IjpbMTAwLDIwLDEwXX0."); } TEST(NlohmannTest, SetObject) { std::istringstream iss{"{\"api-x\": [1]}"}; jwt::basic_claim object; iss >> object; ASSERT_EQ(object.get_type() , jwt::json::type::object); auto token = jwt::create() .set_payload_claim("namespace", object) .sign(jwt::algorithm::hs256("test")); ASSERT_EQ(token, "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lc3BhY2UiOnsiYXBpLXgiOlsxXX19.F8I6I2RcSF98bKa0IpIz09fRZtHr1CWnWKx2za-tFQA"); } TEST(NlohmannTest, VerifyTokenHS256) { std::string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; auto verify = jwt::verify({}) .allow_algorithm(jwt::algorithm::hs256{ "secret" }) .with_issuer("auth0"); auto decoded_token = jwt::decode(token); verify.verify(decoded_token); } TEST(NlohmannTest, VerifyTokenExpirationValid) { const auto token = jwt::create() .set_issuer("auth0") .set_issued_at(std::chrono::system_clock::now()) .set_expires_at(std::chrono::system_clock::now() + std::chrono::seconds{3600}) .sign(jwt::algorithm::hs256{"secret"}); auto verify = jwt::verify({}) .allow_algorithm(jwt::algorithm::hs256{ "secret" }) .with_issuer("auth0"); auto decoded_token = jwt::decode(token); verify.verify(decoded_token); } TEST(NlohmannTest, VerifyTokenExpired) { const auto token = jwt::create() .set_issuer("auth0") .set_issued_at(std::chrono::system_clock::now() - std::chrono::seconds{3601}) .set_expires_at(std::chrono::system_clock::now() - std::chrono::seconds{1}) .sign(jwt::algorithm::hs256{"secret"}); auto verify = jwt::verify({}) .allow_algorithm(jwt::algorithm::hs256{ "secret" }) .with_issuer("auth0"); auto decoded_token = jwt::decode(token); ASSERT_THROW(verify.verify(decoded_token), jwt::token_verification_exception); std::error_code ec; ASSERT_NO_THROW(verify.verify(decoded_token, ec)); ASSERT_TRUE(!(!ec)); ASSERT_EQ(ec.category(), jwt::error::token_verification_error_category()); ASSERT_EQ(ec.value(), static_cast(jwt::error::token_verification_error::token_expired)); }