Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions jwt_verify_lib/jwt.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ struct Jwt {
// payload string
std::string payload_str_;
// payload base64_url encoded
// This is the original encoded payload parsed from `jwt_` and should be the one
// used in the jwt verification.
std::string payload_str_base64url_;
// payload base64_url encoded with padding
std::string payload_str_base64url_padded_;
// payload in Struct protobuf
::google::protobuf::Struct payload_pb_;
// signature string
Expand Down
7 changes: 7 additions & 0 deletions src/jwt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,13 @@ Status Jwt::parseFromString(const std::string& jwt) {
return Status::JwtPayloadParseErrorBadBase64;
}

payload_str_base64url_padded_ = payload_str_base64url_;
if (payload_str_base64url_padded_.length() % 4 != 0) {
std::string trailing_padding(4 - payload_str_base64url_padded_.length() % 4,
'=');
payload_str_base64url_padded_.append(trailing_padding);
}

const auto payload_status = ::google::protobuf::util::JsonStringToMessage(
payload_str_, &payload_pb_, options);
if (!payload_status.ok()) {
Expand Down
74 changes: 74 additions & 0 deletions test/jwt_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "jwt_verify_lib/jwt.h"

#include "google/protobuf/util/message_differencer.h"
#include "absl/strings/escaping.h"
#include "gtest/gtest.h"
#include "jwt_verify_lib/struct_utils.h"

Expand Down Expand Up @@ -69,6 +70,79 @@ TEST(JwtParseTest, GoodJwt) {
EXPECT_EQ(int_value, 1234);
}


TEST(JwtParseTest, PayloadStrBase64UrlPadded) {
struct PayloadStrBase64UrlTestCases {
std::string jwt, payload_str_base64url, payload_str_base64url_padded;
};

// For base64 encoding, there are only three length to test"
// - 3n bytes => 4n bytes, no padding needed
// - 3n + 1 bytes => 4n + 2 bytes, 2 padding needed
// - 3n + 2 bytes => 4n + 3 bytes, 1 padding needed
PayloadStrBase64UrlTestCases testCases[3] = {
// Payload text(3n bytes):
// {
// "sub": "1234567890",
// "name": "John Do",
// "iat": 1516239022
// }
{"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG8iLCJpYXQiOjE1MTYyMzkwMjJ"
"9.9twuPVu9Wj3PBneGw1ctrf3knr7RX12v-UwocfLhXIs",
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG8iLCJpYXQiOjE1MTYyMzkwMjJ"
"9",
// No padding added.
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG8iLCJpYXQiOjE1MTYyMzkwMjJ"
"9"},
// Payload text(3n + 1 bytes):
// {
// "sub": "1234567890",
// "name": "John Doe",
// "iat": 1516239022
// }
{"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDI"
"y"
"fQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2"
"MjM5MDIyfQ",
// 2 padding added.
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2"
"MjM5MDIyfQ=="},
// Payload text(3n + 2 bytes):
// {
// "sub": "1234567890",
// "name": "John Doee",
// "iat": 1516239022
// }
{"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lZSIsImlhdCI6MTUxNjIzOTA"
"y"
"Mn0.1UeFWsD4eTCfiDfgrzySimOvCkKln7pwjQIV5fe4A1Y",
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lZSIsImlhdCI6MTUx"
"NjIzOTAyMn0",
// 1 padding added.
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lZSIsImlhdCI6MTUx"
"NjIzOTAyMn0="}};
for (int i = 0; i < 3; i++) {
struct PayloadStrBase64UrlTestCases& tc = testCases[i];

Jwt jwt;
ASSERT_EQ(jwt.parseFromString(tc.jwt), Status::Ok);

EXPECT_EQ(jwt.payload_str_base64url_, tc.payload_str_base64url);
EXPECT_EQ(jwt.payload_str_base64url_padded_,
tc.payload_str_base64url_padded);

std::string decoded_payload_from_padded_str;
EXPECT_TRUE(absl::WebSafeBase64Unescape(jwt.payload_str_base64url_padded_,
&decoded_payload_from_padded_str));

EXPECT_EQ(decoded_payload_from_padded_str, jwt.payload_str_);
}
}

TEST(JwtParseTest, Copy) {
Jwt original;
ASSERT_EQ(original.parseFromString(good_jwt), Status::Ok);
Expand Down