@@ -1009,7 +1009,21 @@ struct mcp_auth_client {
10091009struct mcp_auth_validation_options {
10101010 std::string scopes;
10111011 std::string audience;
1012- int64_t clock_skew = 60 ;
1012+ int64_t clock_skew = 60 ; // Default: 60 seconds
1013+
1014+ // Constructor with defaults
1015+ mcp_auth_validation_options ()
1016+ : clock_skew(60 ) {} // Ensure default is set
1017+
1018+ // Helper to check if options require scope validation
1019+ bool requires_scope_validation () const {
1020+ return !scopes.empty ();
1021+ }
1022+
1023+ // Helper to check if options require audience validation
1024+ bool requires_audience_validation () const {
1025+ return !audience.empty ();
1026+ }
10131027};
10141028
10151029// Store error in client structure with context (moved after struct definition)
@@ -1537,9 +1551,13 @@ mcp_auth_error_t mcp_auth_validation_options_create(
15371551
15381552 try {
15391553 *options = new mcp_auth_validation_options ();
1554+ // Options are already initialized with defaults via constructor
1555+ // clock_skew = 60, scopes = "", audience = ""
15401556 return MCP_AUTH_SUCCESS;
15411557 } catch (const std::exception& e) {
1542- set_error (MCP_AUTH_ERROR_OUT_OF_MEMORY, e.what ());
1558+ set_error_with_context (MCP_AUTH_ERROR_OUT_OF_MEMORY,
1559+ " Failed to create validation options" ,
1560+ std::string (" Exception: " ) + e.what ());
15431561 return MCP_AUTH_ERROR_OUT_OF_MEMORY;
15441562 }
15451563}
@@ -1586,7 +1604,22 @@ mcp_auth_error_t mcp_auth_validation_options_set_scopes(
15861604 }
15871605
15881606 clear_error ();
1589- options->scopes = scopes ? scopes : " " ;
1607+
1608+ // Validate and normalize scope string
1609+ if (scopes) {
1610+ // Trim whitespace from scopes
1611+ std::string scope_str (scopes);
1612+ size_t first = scope_str.find_first_not_of (' ' );
1613+ if (first != std::string::npos) {
1614+ size_t last = scope_str.find_last_not_of (' ' );
1615+ options->scopes = scope_str.substr (first, (last - first + 1 ));
1616+ } else {
1617+ options->scopes = " " ; // All whitespace
1618+ }
1619+ } else {
1620+ options->scopes = " " ; // Clear scopes if NULL
1621+ }
1622+
15901623 return MCP_AUTH_SUCCESS;
15911624}
15921625
@@ -1605,7 +1638,25 @@ mcp_auth_error_t mcp_auth_validation_options_set_audience(
16051638 }
16061639
16071640 clear_error ();
1608- options->audience = audience ? audience : " " ;
1641+
1642+ // Validate and store audience
1643+ if (audience) {
1644+ // Trim whitespace from audience
1645+ std::string aud_str (audience);
1646+ size_t first = aud_str.find_first_not_of (' ' );
1647+ if (first != std::string::npos) {
1648+ size_t last = aud_str.find_last_not_of (' ' );
1649+ options->audience = aud_str.substr (first, (last - first + 1 ));
1650+ } else {
1651+ options->audience = " " ; // All whitespace
1652+ }
1653+
1654+ // Optionally validate audience format (e.g., URL or identifier)
1655+ // For now, accept any non-empty string
1656+ } else {
1657+ options->audience = " " ; // Clear audience if NULL
1658+ }
1659+
16091660 return MCP_AUTH_SUCCESS;
16101661}
16111662
@@ -1624,6 +1675,20 @@ mcp_auth_error_t mcp_auth_validation_options_set_clock_skew(
16241675 }
16251676
16261677 clear_error ();
1678+
1679+ // Validate clock skew range
1680+ if (seconds < 0 ) {
1681+ set_error_with_context (MCP_AUTH_ERROR_INVALID_CONFIG,
1682+ " Invalid clock skew" ,
1683+ " Clock skew must be non-negative: " + std::to_string (seconds));
1684+ return MCP_AUTH_ERROR_INVALID_CONFIG;
1685+ }
1686+
1687+ // Warn if clock skew is unusually large (> 5 minutes)
1688+ if (seconds > 300 ) {
1689+ fprintf (stderr, " Warning: Large clock skew configured: %lld seconds\n " , (long long )seconds);
1690+ }
1691+
16271692 options->clock_skew = seconds;
16281693 return MCP_AUTH_SUCCESS;
16291694}
@@ -1800,8 +1865,8 @@ mcp_auth_error_t mcp_auth_validate_token(
18001865 }
18011866 }
18021867
1803- // Validate audience if specified
1804- if (options && ! options->audience . empty ()) {
1868+ // Validate audience if specified (using helper method for clarity)
1869+ if (options && options->requires_audience_validation ()) {
18051870 if (payload_data.audience .empty ()) {
18061871 set_error (MCP_AUTH_ERROR_INVALID_AUDIENCE, " JWT has no audience claim" );
18071872 result->error_code = MCP_AUTH_ERROR_INVALID_AUDIENCE;
@@ -1820,8 +1885,8 @@ mcp_auth_error_t mcp_auth_validate_token(
18201885 }
18211886 }
18221887
1823- // Validate scopes if required
1824- if (options && ! options->scopes . empty ()) {
1888+ // Validate scopes if required (using helper method for clarity)
1889+ if (options && options->requires_scope_validation ()) {
18251890 if (payload_data.scopes .empty ()) {
18261891 set_error (MCP_AUTH_ERROR_INSUFFICIENT_SCOPE, " JWT has no scope claim" );
18271892 result->error_code = MCP_AUTH_ERROR_INSUFFICIENT_SCOPE;
0 commit comments