Skip to content

Conversation

@okumin
Copy link
Contributor

@okumin okumin commented Nov 10, 2025

The current implementation stores the retrieved access token in AuthSession#headers, and the AuthSession and its headers are reused. This causes the OAuth2Manager sends an access token via the Authorization header as well as client ID and credential via the request-body at the next access token retrieval. I found Okta could not process such a request.

Reading RFC 6749, I guess we should have supported the basic auth. However, it is unclear all Iceberg environments can use the basic authentication anywhere. So, this pull request retains the policy by just removing the Authorization header from the token request.

Reproduction with curl

I would be able to successfully fetch an access token without the Authorization header.

% curl --request POST \
  --url "https://$OKTA_HOST/oauth2/$OKTA_APP_ID/v1/token" \
  --header 'accept: application/json' \
  --header 'cache-control: no-cache' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data "grant_type=client_credentials&scope=catalog&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET"
{"token_type":"Bearer","expires_in":3600,"access_token":"eyJraWQ...","scope":"catalog"}

However, with the Authorization header, Okta rejects a request.

% curl --request POST \
  --url "https://$OKTA_HOST/oauth2/$OKTA_APP_ID/v1/token" \
  --header 'accept: application/json' \
  --header 'authorization: Bearer yJraWQ...' \
  --header 'cache-control: no-cache' \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data "grant_type=client_credentials&scope=catalog&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET"
{"errorCode":"invalid_client","errorSummary":"No client credentials found.","errorLink":"invalid_client","errorId":"oaeEin5lLeIRkeFNOSXPBrsLQ","errorCauses":[]}

This is the stacktrace I encountered.

Caused by: org.apache.iceberg.exceptions.RESTException: Unable to process: {"errorCode":"invalid_client","errorSummary":"No client credentials found.","errorLink":"invalid_client","errorId":"oaeFeryoPYSR8q6IDMlSqNVrA","errorCauses":[]}
	at org.apache.iceberg.rest.ErrorHandlers$OAuthErrorHandler.accept(ErrorHandlers.java:281)
	at org.apache.iceberg.rest.ErrorHandlers$OAuthErrorHandler.accept(ErrorHandlers.java:252)
	at org.apache.iceberg.rest.HTTPClient.throwFailure(HTTPClient.java:215)
	at org.apache.iceberg.rest.HTTPClient.execute(HTTPClient.java:299)
	at org.apache.iceberg.rest.BaseHTTPClient.postForm(BaseHTTPClient.java:111)
	at org.apache.iceberg.rest.auth.OAuth2Util.fetchToken(OAuth2Util.java:267)
	at org.apache.iceberg.rest.auth.OAuth2Util$AuthSession.fromCredential(OAuth2Util.java:709)
	at org.apache.iceberg.rest.auth.OAuth2Manager.newSessionFromCredential(OAuth2Manager.java:219)
	at org.apache.iceberg.rest.auth.OAuth2Manager.lambda$maybeCreateChildSession$2(OAuth2Manager.java:193)
	at com.github.benmanes.caffeine.cache.BoundedLocalCache.lambda$doComputeIfAbsent$14(BoundedLocalCache.java:2704)
	at java.base/java.util.concurrent.ConcurrentHashMap.compute(ConcurrentHashMap.java:1932)
	at com.github.benmanes.caffeine.cache.BoundedLocalCache.doComputeIfAbsent(BoundedLocalCache.java:2702)
	at com.github.benmanes.caffeine.cache.BoundedLocalCache.computeIfAbsent(BoundedLocalCache.java:2684)
	at com.github.benmanes.caffeine.cache.LocalCache.computeIfAbsent(LocalCache.java:112)
	at com.github.benmanes.caffeine.cache.LocalManualCache.get(LocalManualCache.java:63)
	at org.apache.iceberg.rest.auth.AuthSessionCache.cachedSession(AuthSessionCache.java:88)
	at org.apache.iceberg.rest.auth.OAuth2Manager.maybeCreateChildSession(OAuth2Manager.java:191)
	at org.apache.iceberg.rest.auth.OAuth2Manager.contextualSession(OAuth2Manager.java:140)
	at org.apache.iceberg.rest.auth.OAuth2Manager.contextualSession(OAuth2Manager.java:40)
	at org.apache.iceberg.rest.RESTSessionCatalog.loadInternal(RESTSessionCatalog.java:370)
	at org.apache.iceberg.rest.RESTSessionCatalog.loadTable(RESTSessionCatalog.java:397)
	at io.trino.plugin.iceberg.catalog.rest.TrinoRestCatalog.lambda$loadTable$0(TrinoRestCatalog.java:505)

@github-actions github-actions bot added the core label Nov 10, 2025
@okumin okumin force-pushed the oauth2-client-credentials branch from 3509194 to e56afb7 Compare November 11, 2025 08:11
@okumin okumin marked this pull request as ready for review November 11, 2025 09:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant