cpp/jwt.cc (63 lines of code) (raw):

#include "cpp/jwt.h" #include <exception> #include <string> #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/str_join.h" #include "absl/types/span.h" #include "jwt-cpp/jwt.h" #include "jwt-cpp/traits/nlohmann-json/defaults.h" #include "jwt-cpp/traits/nlohmann-json/traits.h" namespace agent_communication { using decoded_jwt_t = ::jwt::decoded_jwt<jwt::traits::nlohmann_json>; namespace { // Anonymous helper function to decode a JWT token. static absl::StatusOr<decoded_jwt_t> DecodeJwt(const std::string& token) { try { decoded_jwt_t decoded = jwt::decode(token); return decoded; } catch (const std::exception& e) { return absl::InternalError( absl::StrCat("Failed to decode token: ", e.what())); } } } // namespace absl::StatusOr<std::string> GetValueFromTokenPayloadWithKeys( const std::string& token, absl::Span<const std::string> keys) { try { if (keys.empty() || token.empty()) { return absl::InvalidArgumentError("Keys/token cannot be empty."); } absl::StatusOr<decoded_jwt_t> decoded = DecodeJwt(token); if (!decoded.ok()) { return decoded.status(); } jwt::traits::nlohmann_json::json json_obj = decoded->get_payload_json(); for (const std::string& key : keys) { if (!json_obj.is_object()) { return absl::InternalError( absl::StrCat("Token has an invalid format: ", json_obj.dump())); } if (!json_obj.contains(key)) { return absl::InternalError(absl::StrFormat( "Token: %s does not contain key: %s.", json_obj.dump(), key)); } json_obj = json_obj[key]; } if (json_obj.is_number()) { return json_obj.dump(); } if (json_obj.is_string()) { return json_obj.get<std::string>(); } return absl::InternalError(absl::StrFormat( "Token %s does not have a string/number value for key (%s): ", json_obj.dump(), absl::StrJoin(keys, ","))); } catch (const std::exception& e) { // The try-catch is to catch the exception thrown by the jwt-cpp // library. This is probably redundant since we already have the try-catch // in DecodeJwt, which is the only place where I suspect the exception can // throw. We add this outer try-catch to make the code more robust // and prevent exception leak into google3. return absl::InternalError(absl::StrFormat( "Failed to get value of key (%s) from token %s: due to exception: %s", absl::StrJoin(keys, ","), token, e.what())); } } } // namespace agent_communication