@@ -433,7 +433,7 @@ std::string scitokens::Validator::load_jwks(const std::string &issuer) {
433433 auto now = std::time (NULL );
434434 picojson::value jwks;
435435 int64_t next_update;
436-
436+
437437 try {
438438 // Try to get from cache
439439 if (get_public_keys_from_db (issuer, now, jwks, next_update)) {
@@ -448,12 +448,12 @@ std::string scitokens::Validator::load_jwks(const std::string &issuer) {
448448 // Negative cache hit - return empty keys
449449 return std::string (" {\" keys\" : []}" );
450450 }
451-
451+
452452 // Either not in cache or past next_update - refresh
453453 if (!refresh_jwks (issuer)) {
454454 throw CurlException (" Failed to load JWKS for issuer: " + issuer);
455455 }
456-
456+
457457 // Get the newly refreshed JWKS
458458 return get_jwks (issuer);
459459}
@@ -462,57 +462,57 @@ std::string scitokens::Validator::get_jwks_metadata(const std::string &issuer) {
462462 auto now = std::time (NULL );
463463 int64_t next_update = -1 ;
464464 int64_t expires = -1 ;
465-
465+
466466 // Get the metadata from database without expiry check
467467 auto cache_fname = get_cache_file ();
468468 if (cache_fname.size () == 0 ) {
469469 throw std::runtime_error (" Unable to access cache file" );
470470 }
471-
471+
472472 sqlite3 *db;
473473 int rc = sqlite3_open (cache_fname.c_str (), &db);
474474 if (rc) {
475475 sqlite3_close (db);
476476 throw std::runtime_error (" Failed to open cache database" );
477477 }
478478 sqlite3_busy_timeout (db, SQLITE_BUSY_TIMEOUT_MS);
479-
479+
480480 sqlite3_stmt *stmt;
481481 rc = sqlite3_prepare_v2 (db, " SELECT keys from keycache where issuer = ?" ,
482482 -1 , &stmt, NULL );
483483 if (rc != SQLITE_OK) {
484484 sqlite3_close (db);
485485 throw std::runtime_error (" Failed to prepare database query" );
486486 }
487-
487+
488488 if (sqlite3_bind_text (stmt, 1 , issuer.c_str (), issuer.size (),
489489 SQLITE_STATIC) != SQLITE_OK) {
490490 sqlite3_finalize (stmt);
491491 sqlite3_close (db);
492492 throw std::runtime_error (" Failed to bind issuer to query" );
493493 }
494-
494+
495495 rc = sqlite3_step (stmt);
496496 if (rc == SQLITE_ROW) {
497497 const unsigned char *data = sqlite3_column_text (stmt, 0 );
498498 std::string metadata (reinterpret_cast <const char *>(data));
499499 sqlite3_finalize (stmt);
500500 sqlite3_close (db);
501-
501+
502502 picojson::value json_obj;
503503 auto err = picojson::parse (json_obj, metadata);
504504 if (!err.empty () || !json_obj.is <picojson::object>()) {
505505 throw JsonException (" Invalid JSON in cache entry" );
506506 }
507-
507+
508508 auto top_obj = json_obj.get <picojson::object>();
509-
509+
510510 // Extract expires
511511 auto iter = top_obj.find (" expires" );
512512 if (iter != top_obj.end () && iter->second .is <int64_t >()) {
513513 expires = iter->second .get <int64_t >();
514514 }
515-
515+
516516 // Extract next_update
517517 iter = top_obj.find (" next_update" );
518518 if (iter != top_obj.end () && iter->second .is <int64_t >()) {
@@ -521,13 +521,16 @@ std::string scitokens::Validator::get_jwks_metadata(const std::string &issuer) {
521521 // Default next_update to 4 hours before expiry
522522 next_update = expires - DEFAULT_NEXT_UPDATE_OFFSET_S;
523523 }
524-
525- // Build metadata JSON
524+
525+ // Build metadata JSON (add future keys at top level if needed)
526526 picojson::object metadata_obj;
527- metadata_obj[" expires" ] = picojson::value (expires);
528- metadata_obj[" next_update" ] = picojson::value (next_update);
529- metadata_obj[" extra" ] = picojson::value (picojson::object ());
530-
527+ if (expires != -1 ) {
528+ metadata_obj[" expires" ] = picojson::value (expires);
529+ }
530+ if (next_update != -1 ) {
531+ metadata_obj[" next_update" ] = picojson::value (next_update);
532+ }
533+
531534 return picojson::value (metadata_obj).serialize ();
532535 } else {
533536 sqlite3_finalize (stmt);
@@ -541,22 +544,22 @@ bool scitokens::Validator::delete_jwks(const std::string &issuer) {
541544 if (cache_fname.size () == 0 ) {
542545 return false ;
543546 }
544-
547+
545548 sqlite3 *db;
546549 int rc = sqlite3_open (cache_fname.c_str (), &db);
547550 if (rc) {
548551 sqlite3_close (db);
549552 return false ;
550553 }
551554 sqlite3_busy_timeout (db, SQLITE_BUSY_TIMEOUT_MS);
552-
555+
553556 // Use the existing remove_issuer_entry function
554557 // Note: remove_issuer_entry closes the database on error
555558 if (remove_issuer_entry (db, issuer, true ) != 0 ) {
556559 // Database already closed by remove_issuer_entry
557560 return false ;
558561 }
559-
562+
560563 sqlite3_close (db);
561564 return true ;
562565}
0 commit comments