You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by si...@apache.org on 2026/05/30 19:30:28 UTC

(iceberg) branch main updated: Core: Fix optionalOAuthParams dropped during non-exchange token refresh (#16022) (#16023)

This is an automated email from the ASF dual-hosted git repository.

singhpk234 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg.git


The following commit(s) were added to refs/heads/main by this push:
     new f6740364c4 Core: Fix optionalOAuthParams dropped during non-exchange token refresh (#16022) (#16023)
f6740364c4 is described below

commit f6740364c46afb811fd57c8ca965555600f644bc
Author: Bharath Krishna <bm...@roku.com>
AuthorDate: Sat May 30 15:30:21 2026 -0400

    Core: Fix optionalOAuthParams dropped during non-exchange token refresh (#16022) (#16023)
---
 .../org/apache/iceberg/rest/auth/OAuth2Util.java   |  4 +-
 .../apache/iceberg/rest/auth/TestOAuth2Util.java   | 48 ++++++++++++++++++++++
 2 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/core/src/main/java/org/apache/iceberg/rest/auth/OAuth2Util.java b/core/src/main/java/org/apache/iceberg/rest/auth/OAuth2Util.java
index 7a244bff70..a9504a7a4e 100644
--- a/core/src/main/java/org/apache/iceberg/rest/auth/OAuth2Util.java
+++ b/core/src/main/java/org/apache/iceberg/rest/auth/OAuth2Util.java
@@ -190,7 +190,7 @@ public class OAuth2Util {
           config.credential(),
           config.scope(),
           config.oauth2ServerUri(),
-          ImmutableMap.of());
+          optionalOAuthParams);
     }
   }
 
@@ -564,7 +564,7 @@ public class OAuth2Util {
             client, config, basicHeaders, token(), tokenType(), optionalOAuthParams());
       } else {
         return fetchToken(
-            client, Map.of(), credential(), scope(), oauth2ServerUri(), ImmutableMap.of());
+            client, Map.of(), credential(), scope(), oauth2ServerUri(), optionalOAuthParams());
       }
     }
 
diff --git a/core/src/test/java/org/apache/iceberg/rest/auth/TestOAuth2Util.java b/core/src/test/java/org/apache/iceberg/rest/auth/TestOAuth2Util.java
index 4a6fbf7a1c..04f7571eca 100644
--- a/core/src/test/java/org/apache/iceberg/rest/auth/TestOAuth2Util.java
+++ b/core/src/test/java/org/apache/iceberg/rest/auth/TestOAuth2Util.java
@@ -31,6 +31,7 @@ import com.nimbusds.jwt.PlainJWT;
 import java.io.IOException;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
+import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
 import org.apache.iceberg.rest.RESTClient;
 import org.apache.iceberg.rest.auth.OAuth2Util.AuthSession;
 import org.apache.iceberg.rest.responses.OAuthTokenResponse;
@@ -205,6 +206,53 @@ public class TestOAuth2Util {
     }
   }
 
+  @Test
+  void refreshExpiredTokenShouldIncludeOptionalOAuthParams() throws IOException {
+    assertRefreshIncludesOptionalOAuthParams(System.currentTimeMillis() - 10_000);
+  }
+
+  @Test
+  void refreshCurrentTokenNonExchangeShouldIncludeOptionalOAuthParams() throws IOException {
+    assertRefreshIncludesOptionalOAuthParams(System.currentTimeMillis() + 300_000);
+  }
+
+  private static void assertRefreshIncludesOptionalOAuthParams(long expiresAtMillis)
+      throws IOException {
+    String audience = "https://my-catalog.example.com";
+    AuthConfig authConfig =
+        ImmutableAuthConfig.builder()
+            .keepRefreshed(true)
+            .exchangeEnabled(false)
+            .token("token")
+            .credential("testClientId:testClientSecret")
+            .oauth2ServerUri("/v1/token")
+            .expiresAtMillis(expiresAtMillis)
+            .optionalOAuthParams(ImmutableMap.of("audience", audience, "scope", "catalog"))
+            .build();
+
+    OAuthTokenResponse response =
+        OAuthTokenResponse.builder().withToken("refreshed_token").withTokenType(BEARER).build();
+
+    try (RESTClient client = Mockito.mock(RESTClient.class);
+        OAuth2Util.AuthSession session = new OAuth2Util.AuthSession(Map.of(), authConfig)) {
+      Mockito.when(client.postForm(any(), anyMap(), any(), anyMap(), any())).thenReturn(response);
+
+      session.refresh(client);
+
+      Mockito.verify(client)
+          .postForm(
+              any(),
+              argThat(
+                  formData ->
+                      CLIENT_CREDENTIALS.equals(formData.get(GRANT_TYPE))
+                          && audience.equals(formData.get("audience"))
+                          && "catalog".equals(formData.get("scope"))),
+              Mockito.eq(OAuthTokenResponse.class),
+              anyMap(),
+              any());
+    }
+  }
+
   private static AuthSession parentSession(long expSeconds) {
     String parentToken = tokenWithExp(expSeconds);
     AuthConfig parentConfig =