Skip to content

feat: Implement OAuth2 authentication for REST catalog#577

Open
lishuxu wants to merge 3 commits intoapache:mainfrom
lishuxu:feature/oauth
Open

feat: Implement OAuth2 authentication for REST catalog#577
lishuxu wants to merge 3 commits intoapache:mainfrom
lishuxu:feature/oauth

Conversation

@lishuxu
Copy link
Contributor

@lishuxu lishuxu commented Feb 26, 2026

Add OAuth2 authentication support for the REST catalog, including:

  • OAuth2AuthManager with static token and client_credentials grant flows

Also includes:

  • Fix BuildHeaders in http_client.cc to use insert_or_assign so request-specific
    headers properly override defaults

TODO:
RefreshToken and ExchangeToken will be supported later

Copy link
Member

@wgtmac wgtmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a comprehensive code review report generated by gemini-cli against PR #577. The review rigorously compares the C++ implementation with the RFC 6749 (OAuth2) spec and the current Iceberg Java behavior.

Overall, the structure and C++ style are excellent, but there are a few parity and robustness issues that need addressing.

namespace iceberg::rest::auth {

/// \brief Response from an OAuth2 token endpoint.
struct ICEBERG_REST_EXPORT OAuthTokenResponse {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this is defined here but not in the src/iceberg/catalog/rest/types.h?

///
/// \param json_str The JSON string to parse.
/// \return The parsed token response or an error.
ICEBERG_REST_EXPORT Result<OAuthTokenResponse> OAuthTokenResponseFromJsonString(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, should this be moved to src/iceberg/catalog/rest/json_serde_internal.h and also add its ToJson?

struct ICEBERG_REST_EXPORT OAuthTokenResponse {
std::string access_token; // required
std::string token_type; // required, typically "bearer"
int64_t expires_in = 0; // optional, seconds until expiration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int64_t expires_in = 0; // optional, seconds until expiration
std::optional<int64_t> expires_in; // optional, seconds until expiration

Let's use optional because the default 0 will cause trouble.

/// \param scope OAuth2 scope to request.
/// \param session Auth session for the request (typically a no-op session).
/// \return The token response or an error.
ICEBERG_REST_EXPORT Result<OAuthTokenResponse> FetchToken(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks strange that AuthSession& session is required here so we have to create a AuthSession anyway before calling this. Should we use the same input parameter list as the Java api?

const std::string& /*client_id*/, const std::string& /*client_secret*/,
const std::string& /*scope*/, HttpClient& /*client*/) {
// TODO(lishuxu): Create OAuth2AuthSession with auto-refresh support.
return MakeDefault({{"Authorization", "Bearer " + initial_token.access_token}});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid magic string like "Authorization" and "Bearer " by defining them as constants in src/iceberg/catalog/rest/oauth2_util.h?

FetchToken(init_client, ctx.token_endpoint, ctx.client_id,
ctx.client_secret, ctx.scope, *noop_session));
return AuthSession::MakeDefault(
{{"Authorization", "Bearer " + init_token_response_->access_token}});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, let's avoid magic strings scattered around.

// TODO(lishuxu): Override ContextualSession() to support per-context token exchange.

private:
struct OAuth2Context {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this trying to mirror the AuthConfig in Java? Perhaps we should extend it from ConfigBase to accept a map for better extensibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants