Logo Pico-Framework A web-first embedded framework for C++
Loading...
Searching...
No Matches
JwtAuthenticator Class Reference

JWT JwtAuthenticator for embedded applications. More...

#include <JwtAuthenticator.h>

+ Collaboration diagram for JwtAuthenticator:

Public Member Functions

 JwtAuthenticator ()
 Get an instance of the JwtAuthenticator.
 
void init (const std::string &secret, int expirySeconds)
 Initialize the JwtAuthenticator with a secret key and expiry time.
 
std::string generateJWT (const std::string &userId, const std::string &userName) const
 Generate a JWT for a given user.
 
bool validateJWT (const std::string &token, bool validateExpiry=false) const
 Validate a JWT's signature and optionally its expiration.
 
bool decodeJWT (const std::string &token, std::string &header, std::string &payload, std::string &signature) const
 Decode a JWT into its components.
 
bool isJWTExpired (const std::string &token) const
 Check if a JWT is expired based on the exp claim.
 
bool isJWTPayloadExpired (const std::string &payload) const
 Check if a decoded JWT payload is expired.
 
bool verifyJWTSignature (const std::string &encoded_header, const std::string &encoded_payload, const std::string &signature) const
 Verify a JWT's signature using HMAC-SHA256.
 

Private Member Functions

std::string base64urlEncode (const std::string &input) const
 Encode a string using base64url encoding.
 
bool base64urlDecode (const std::string &input, std::string &output) const
 Decode a base64url-encoded string.
 
bool isBase64urlEncoded (const std::string &str) const
 Check if a string is valid base64url.
 
std::string bytesToBase64url (const unsigned char *data, size_t length) const
 Convert a byte buffer to a base64url string.
 
std::string hmacSHA256 (const std::string &message) const
 Calculate HMAC-SHA256 for a given message.
 

Private Attributes

std::string secretKey
 Construct a new JwtAuthenticator object.
 
std::string expiryTime
 

Detailed Description

This class provides helper methods to generate and validate JWT tokens using HMAC-SHA256. It uses a singleton design pattern and is intended to be stateless aside from a secret key.

Definition at line 26 of file JwtAuthenticator.h.

Constructor & Destructor Documentation

◆ JwtAuthenticator()

JwtAuthenticator::JwtAuthenticator ( )

Get an instance of the JwtAuthenticator.

Returns
Reference to the JwtAuthenticator instance.
Returns
Reference to the JwtAuthenticator instance.

Definition at line 39 of file JwtAuthenticator.cpp.

40{
41 secretKey = JWT_SECRET;
42}
std::string secretKey
Construct a new JwtAuthenticator object.

References secretKey.

Member Function Documentation

◆ base64urlDecode()

bool JwtAuthenticator::base64urlDecode ( const std::string &  input,
std::string &  output 
) const
private

Decode a base64url-encoded string.

Parameters
inputEncoded input.
outputDecoded output.
Returns
true if decoding was successful.
Parameters
inputEncoded input.
outputDecoded output.
Returns
true if decoding was successful.

Definition at line 72 of file JwtAuthenticator.cpp.

73{
74 std::string base64_input = input;
75 std::replace(base64_input.begin(), base64_input.end(), '-', '+');
76 std::replace(base64_input.begin(), base64_input.end(), '_', '/');
77 while (base64_input.size() % 4 != 0)
78 {
79 base64_input += "=";
80 }
81
82 for (size_t i = 0; i < base64_input.size(); ++i)
83 {
84 if (static_cast<unsigned char>(base64_input[i]) > 127)
85 {
86 std::cout << "Invalid character found in base64: " << (int)base64_input[i] << std::endl;
87 return false;
88 }
89 }
90
91 size_t decoded_len = base64_input.size() * 3 / 4 + 4;
92 unsigned char *decoded_data = new unsigned char[decoded_len];
93
94 int ret = mbedtls_base64_decode(decoded_data, decoded_len, &decoded_len,
95 (const unsigned char *)base64_input.c_str(), base64_input.size());
96
97 if (ret != 0)
98 {
99 char error_msg[100];
100 mbedtls_strerror(ret, error_msg, sizeof(error_msg));
101 std::cerr << "Base64 decoding failed: " << error_msg << std::endl;
102 delete[] decoded_data;
103 return false;
104 }
105
106 output.assign(reinterpret_cast<char *>(decoded_data), decoded_len);
107 delete[] decoded_data;
108 return true;
109}

Referenced by decodeJWT(), isJWTExpired(), and validateJWT().

+ Here is the caller graph for this function:

◆ base64urlEncode()

std::string JwtAuthenticator::base64urlEncode ( const std::string &  input) const
private

Encode a string using base64url encoding.

Parameters
inputRaw input string.
Returns
Base64url-encoded string.
Parameters
inputRaw input string.
Returns
Base64url-encoded string.

Definition at line 45 of file JwtAuthenticator.cpp.

46{
47 size_t encoded_len = ((input.length() + 2) / 3) * 4 + 1;
48 char *encoded_data = new char[encoded_len];
49
50 size_t len = 0;
51 int result = mbedtls_base64_encode(reinterpret_cast<unsigned char *>(encoded_data), encoded_len, &len,
52 reinterpret_cast<const unsigned char *>(input.c_str()), input.length());
53
54 if (result != 0)
55 {
56 std::cerr << "Base64 encoding failed with error code: " << result << std::endl;
57 delete[] encoded_data;
58 return "";
59 }
60
61 std::string base64_str(encoded_data, len);
62 std::string base64url_str(base64_str);
63 std::replace(base64url_str.begin(), base64url_str.end(), '+', '-');
64 std::replace(base64url_str.begin(), base64url_str.end(), '/', '_');
65 base64url_str.erase(std::remove(base64url_str.begin(), base64url_str.end(), '='), base64url_str.end());
66
67 delete[] encoded_data;
68 return base64url_str;
69}

Referenced by generateJWT().

+ Here is the caller graph for this function:

◆ bytesToBase64url()

std::string JwtAuthenticator::bytesToBase64url ( const unsigned char *  data,
size_t  length 
) const
private

Convert a byte buffer to a base64url string.

Parameters
dataByte array.
lengthLength of array.
Returns
Base64url string.
Parameters
dataByte array.
lengthLength of array.
Returns
Base64url string.

Definition at line 201 of file JwtAuthenticator.cpp.

202{
203 size_t output_len = length * 4 / 3 + 4;
204 char *base64_output = new char[output_len];
205 size_t written_len = 0;
206
207 mbedtls_base64_encode((unsigned char *)base64_output, output_len, &written_len, data, length);
208
209 std::string base64_result(base64_output, written_len);
210 std::replace(base64_result.begin(), base64_result.end(), '+', '-');
211 std::replace(base64_result.begin(), base64_result.end(), '/', '_');
212 base64_result.erase(std::remove(base64_result.end() - 1, base64_result.end(), '='), base64_result.end());
213
214 delete[] base64_output;
215 return base64_result;
216}

Referenced by verifyJWTSignature().

+ Here is the caller graph for this function:

◆ decodeJWT()

bool JwtAuthenticator::decodeJWT ( const std::string &  token,
std::string &  header,
std::string &  payload,
std::string &  signature 
) const

Decode a JWT into its components.

Parameters
tokenJWT string.
headerOutput decoded header JSON string.
payloadOutput decoded payload JSON string.
signatureOutput base64url-encoded signature.
Returns
true if decoding was successful.
Parameters
tokenJWT string.
headerOutput decoded header JSON string.
payloadOutput decoded payload JSON string.
signatureOutput base64url-encoded signature.
Returns
true if decoding was successful.

Definition at line 168 of file JwtAuthenticator.cpp.

169{
170 size_t first_dot = token.find('.');
171 size_t second_dot = token.find('.', first_dot + 1);
172 if (first_dot == std::string::npos || second_dot == std::string::npos)
173 {
174 return false;
175 }
176
177 header = token.substr(0, first_dot);
178 payload = token.substr(first_dot + 1, second_dot - first_dot - 1);
179 signature = token.substr(second_dot + 1);
180
181 if (isBase64urlEncoded(header))
182 {
183 std::string decoded;
184 if (!base64urlDecode(header, decoded))
185 return false;
186 header = decoded;
187 }
188
189 if (isBase64urlEncoded(payload))
190 {
191 std::string decoded;
192 if (!base64urlDecode(payload, decoded))
193 return false;
194 payload = decoded;
195 }
196
197 return true;
198}
bool base64urlDecode(const std::string &input, std::string &output) const
Decode a base64url-encoded string.
bool isBase64urlEncoded(const std::string &str) const
Check if a string is valid base64url.

References base64urlDecode(), and isBase64urlEncoded().

+ Here is the call graph for this function:

◆ generateJWT()

std::string JwtAuthenticator::generateJWT ( const std::string &  userId,
const std::string &  userName 
) const

Generate a JWT for a given user.

Parameters
userIdUser ID (used as the sub claim).
userNameUser name (stored in name claim).
Returns
A signed JWT string.
Parameters
userIdUser ID (used as the sub claim).
userNameUser name (stored in name claim).
Returns
A signed JWT string.

Definition at line 150 of file JwtAuthenticator.cpp.

151{
152 json header = {{"alg", "HS256"}, {"typ", "JWT"}};
153 json payload = {
154 {"sub", userId},
155 {"name", userName},
156 {"iat", std::time(0)},
157 {"exp", std::time(0) + 3600}};
158
159 std::string encodedHeader = base64urlEncode(header.dump());
160 std::string encodedPayload = base64urlEncode(payload.dump());
161 std::string message = encodedHeader + "." + encodedPayload;
162 std::string signature = base64urlEncode(hmacSHA256(message));
163
164 return encodedHeader + "." + encodedPayload + "." + signature;
165}
nlohmann::json json
std::string base64urlEncode(const std::string &input) const
Encode a string using base64url encoding.
std::string hmacSHA256(const std::string &message) const
Calculate HMAC-SHA256 for a given message.

References base64urlEncode(), and hmacSHA256().

+ Here is the call graph for this function:

◆ hmacSHA256()

std::string JwtAuthenticator::hmacSHA256 ( const std::string &  message) const
private

Calculate HMAC-SHA256 for a given message.

Parameters
messageInput string.
Returns
Binary HMAC result.
Parameters
messageInput string.
Returns
Binary HMAC result.

Definition at line 133 of file JwtAuthenticator.cpp.

134{
135 unsigned char hmac_output[MBEDTLS_SHA256_DIGEST_LENGTH];
136 mbedtls_md_context_t ctx;
137
138 mbedtls_md_init(&ctx);
139 const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
140 mbedtls_md_setup(&ctx, md_info, 1);
141 mbedtls_md_hmac_starts(&ctx, reinterpret_cast<const unsigned char *>(secretKey.c_str()), secretKey.size());
142 mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char *>(message.c_str()), message.size());
143 mbedtls_md_hmac_finish(&ctx, hmac_output);
144 mbedtls_md_free(&ctx);
145
146 return std::string(reinterpret_cast<char *>(hmac_output), MBEDTLS_SHA256_DIGEST_LENGTH);
147}
#define MBEDTLS_SHA256_DIGEST_LENGTH

References MBEDTLS_SHA256_DIGEST_LENGTH, and secretKey.

Referenced by generateJWT().

+ Here is the caller graph for this function:

◆ init()

void JwtAuthenticator::init ( const std::string &  secret,
int  expirySeconds 
)
Parameters
secretSecret key for HMAC-SHA256 signing.
expirySecondsExpiry time in seconds.

Definition at line 299 of file JwtAuthenticator.cpp.

300{
301 this->secretKey = secret;
302 this->expiryTime = expirySeconds;
303}
std::string expiryTime

References expiryTime, and secretKey.

◆ isBase64urlEncoded()

bool JwtAuthenticator::isBase64urlEncoded ( const std::string &  str) const
private

Check if a string is valid base64url.

Parameters
strString to check.
Returns
true if string is valid base64url.
Parameters
strString to check.
Returns
true if string is valid base64url.

Definition at line 112 of file JwtAuthenticator.cpp.

113{
114 static const std::string base64url_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
115
116 if (str.length() % 4 != 0)
117 {
118 return false;
119 }
120
121 for (char c : str)
122 {
123 if (base64url_chars.find(c) == std::string::npos)
124 {
125 return false;
126 }
127 }
128
129 return true;
130}

Referenced by decodeJWT().

+ Here is the caller graph for this function:

◆ isJWTExpired()

bool JwtAuthenticator::isJWTExpired ( const std::string &  token) const

Check if a JWT is expired based on the exp claim.

Parameters
tokenJWT string.
Returns
true if expired, false if valid or error.
Parameters
tokenJWT string.
Returns
true if expired, false if valid or error.

Definition at line 257 of file JwtAuthenticator.cpp.

258{
259 size_t first_dot = token.find('.');
260 size_t second_dot = token.find('.', first_dot + 1);
261 if (first_dot == std::string::npos || second_dot == std::string::npos)
262 return false;
263
264 std::string encoded_payload = token.substr(first_dot + 1, second_dot - first_dot - 1);
265 std::string decoded_payload;
266
267 if (!base64urlDecode(encoded_payload, decoded_payload))
268 return false;
269 return isJWTPayloadExpired(decoded_payload);
270}
bool isJWTPayloadExpired(const std::string &payload) const
Check if a decoded JWT payload is expired.

References base64urlDecode(), and isJWTPayloadExpired().

+ Here is the call graph for this function:

◆ isJWTPayloadExpired()

bool JwtAuthenticator::isJWTPayloadExpired ( const std::string &  payload) const

Check if a decoded JWT payload is expired.

Parameters
payloadDecoded payload string (JSON).
Returns
true if expired, false otherwise.
Parameters
payloadDecoded payload string (JSON).
Returns
true if expired, false otherwise.

Definition at line 239 of file JwtAuthenticator.cpp.

240{
241 auto parsed = json::parse(payload, nullptr, false);
242 if (parsed.is_discarded() || !parsed.contains("exp") || !parsed["exp"].is_number_integer())
243 {
244 std::cerr << "Invalid or missing 'exp' in JWT payload." << std::endl;
245 return false;
246 }
247
248 long long exp_timestamp = parsed["exp"].get<long long>();
249 if (exp_timestamp <= 0)
250 return false;
251
252 auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
253 return now >= exp_timestamp;
254}

Referenced by isJWTExpired(), and validateJWT().

+ Here is the caller graph for this function:

◆ validateJWT()

bool JwtAuthenticator::validateJWT ( const std::string &  token,
bool  validateExpiry = false 
) const

Validate a JWT's signature and optionally its expiration.

Parameters
tokenJWT string.
validateExpiryWhether to check the exp claim.
Returns
true if valid and optionally not expired.
Parameters
tokenJWT string.
validateExpiryWhether to check the exp claim.
Returns
true if valid and optionally not expired.

Definition at line 273 of file JwtAuthenticator.cpp.

274{
275 size_t first_dot = token.find('.');
276 size_t second_dot = token.find('.', first_dot + 1);
277 if (first_dot == std::string::npos || second_dot == std::string::npos)
278 return false;
279
280 std::string encoded_header = token.substr(0, first_dot);
281 std::string encoded_payload = token.substr(first_dot + 1, second_dot - first_dot - 1);
282 std::string signature = token.substr(second_dot + 1);
283
284 std::string decoded_header, decoded_payload;
285 if (!base64urlDecode(encoded_header, decoded_header) ||
286 !base64urlDecode(encoded_payload, decoded_payload))
287 {
288 return false;
289 }
290
291 if (validateExpiry && isJWTPayloadExpired(decoded_payload))
292 {
293 return false;
294 }
295
296 return verifyJWTSignature(encoded_header, encoded_payload, signature);
297}
bool verifyJWTSignature(const std::string &encoded_header, const std::string &encoded_payload, const std::string &signature) const
Verify a JWT's signature using HMAC-SHA256.

References base64urlDecode(), isJWTPayloadExpired(), and verifyJWTSignature().

+ Here is the call graph for this function:

◆ verifyJWTSignature()

bool JwtAuthenticator::verifyJWTSignature ( const std::string &  encoded_header,
const std::string &  encoded_payload,
const std::string &  signature 
) const

Verify a JWT's signature using HMAC-SHA256.

Parameters
encoded_headerBase64url-encoded JWT header.
encoded_payloadBase64url-encoded JWT payload.
signatureBase64url-encoded signature to verify against.
Returns
true if the signature is valid.
Parameters
encoded_headerBase64url-encoded JWT header.
encoded_payloadBase64url-encoded JWT payload.
signatureBase64url-encoded signature to verify against.
Returns
true if the signature is valid.

Definition at line 219 of file JwtAuthenticator.cpp.

220{
221 std::string header_payload = encoded_header + "." + encoded_payload;
222
223 mbedtls_md_context_t ctx;
224 mbedtls_md_init(&ctx);
225 const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
226 mbedtls_md_setup(&ctx, md_info, 1);
227 mbedtls_md_hmac_starts(&ctx, (const unsigned char *)secretKey.c_str(), secretKey.length());
228 mbedtls_md_hmac_update(&ctx, (const unsigned char *)header_payload.c_str(), header_payload.length());
229
230 unsigned char hmac_output[MBEDTLS_SHA256_DIGEST_LENGTH];
231 mbedtls_md_hmac_finish(&ctx, hmac_output);
232 mbedtls_md_free(&ctx);
233
234 std::string computed_signature = bytesToBase64url(hmac_output, MBEDTLS_SHA256_DIGEST_LENGTH);
235 return computed_signature == signature;
236}
std::string bytesToBase64url(const unsigned char *data, size_t length) const
Convert a byte buffer to a base64url string.

References bytesToBase64url(), MBEDTLS_SHA256_DIGEST_LENGTH, and secretKey.

Referenced by validateJWT().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Member Data Documentation

◆ expiryTime

std::string JwtAuthenticator::expiryTime
private

Definition at line 99 of file JwtAuthenticator.h.

Referenced by init().

◆ secretKey

std::string JwtAuthenticator::secretKey
private

Secret key is loaded from build config.

Definition at line 98 of file JwtAuthenticator.h.

Referenced by hmacSHA256(), init(), JwtAuthenticator(), and verifyJWTSignature().


The documentation for this class was generated from the following files: