Skip to content

Commit 0e741b9

Browse files
author
shuxu.li
committed
feat: Implement OAuth2 authentication for REST catalog
1 parent 79e81ae commit 0e741b9

4 files changed

Lines changed: 4 additions & 38 deletions

File tree

‎src/iceberg/catalog/rest/auth/auth_manager.cc‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include "iceberg/catalog/rest/auth/auth_session.h"
2727
#include "iceberg/catalog/rest/auth/oauth2_util.h"
2828
#include "iceberg/catalog/rest/catalog_properties.h"
29-
#include "iceberg/catalog/rest/http_client.h"
3029
#include "iceberg/util/macros.h"
3130
#include "iceberg/util/transform_util.h"
3231

@@ -127,7 +126,6 @@ class OAuth2AuthManager : public AuthManager {
127126
Result<std::shared_ptr<AuthSession>> CatalogSession(
128127
HttpClient& client,
129128
const std::unordered_map<std::string, std::string>& properties) override {
130-
// Reuse the token fetched during InitSession.
131129
if (init_token_response_.has_value()) {
132130
auto token_response = std::move(*init_token_response_);
133131
init_token_response_.reset();
@@ -136,7 +134,7 @@ class OAuth2AuthManager : public AuthManager {
136134
ctx.client_secret, ctx.scope, client);
137135
}
138136

139-
// If both token and credential are provided, prefer the token.
137+
// If token is provided, use it directly.
140138
auto token_it = properties.find(AuthProperties::kOAuth2Token);
141139
if (token_it != properties.end() && !token_it->second.empty()) {
142140
return AuthSession::MakeDefault({{"Authorization", "Bearer " + token_it->second}});

‎src/iceberg/catalog/rest/auth/auth_session.cc‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,7 @@ std::shared_ptr<AuthSession> AuthSession::MakeOAuth2(
5555
const OAuthTokenResponse& initial_token, const std::string& /*token_endpoint*/,
5656
const std::string& /*client_id*/, const std::string& /*client_secret*/,
5757
const std::string& /*scope*/, HttpClient& /*client*/) {
58-
// TODO(lishuxu): Replace with OAuth2AuthSession that:
59-
// - Stores access_token, refresh_token, expires_in, and token_endpoint
60-
// - Checks token expiration in Authenticate() and transparently refreshes
61-
// using RefreshToken() (or re-fetches via client_credentials if no
62-
// refresh_token is available)
63-
// For now, fall back to a static session with the initial token.
58+
// TODO(lishuxu): Create OAuth2AuthSession with auto-refresh support.
6459
return MakeDefault({{"Authorization", "Bearer " + initial_token.access_token}});
6560
}
6661

‎src/iceberg/catalog/rest/auth/oauth2_util.cc‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,13 @@ Result<OAuthTokenResponse> FetchToken(HttpClient& client,
7878
const std::string& client_id,
7979
const std::string& client_secret,
8080
const std::string& scope, AuthSession& session) {
81-
std::unordered_map<std::string, std::string> form_data = {
81+
std::unordered_map<std::string, std::string> form_data{
8282
{std::string(kGrantType), std::string(kClientCredentials)},
8383
{std::string(kClientId), client_id},
8484
{std::string(kClientSecret), client_secret},
8585
};
8686
if (!scope.empty()) {
87-
form_data[std::string(kScope)] = scope;
87+
form_data.emplace(std::string(kScope), scope);
8888
}
8989

9090
ICEBERG_ASSIGN_OR_RAISE(auto response,

‎src/iceberg/catalog/rest/auth/oauth2_util.h‎

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -69,38 +69,11 @@ ICEBERG_REST_EXPORT Result<OAuthTokenResponse> FetchToken(
6969
const std::string& client_secret, const std::string& scope, AuthSession& session);
7070

7171
/// \brief Refresh an expired access token using a refresh_token grant.
72-
///
73-
/// Sends a POST request with form-encoded body to the token endpoint:
74-
/// grant_type=refresh_token&refresh_token=...&client_id=...&scope=...
75-
///
76-
/// \param client HTTP client to use for the request.
77-
/// \param token_endpoint Full URL of the OAuth2 token endpoint.
78-
/// \param client_id OAuth2 client ID (may be empty if not required by server).
79-
/// \param refresh_token The refresh token from a previous token response.
80-
/// \param scope OAuth2 scope to request.
81-
/// \param session Auth session for the request.
82-
/// \return A new token response with a fresh access_token, or an error.
8372
ICEBERG_REST_EXPORT Result<OAuthTokenResponse> RefreshToken(
8473
HttpClient& client, const std::string& token_endpoint, const std::string& client_id,
8574
const std::string& refresh_token, const std::string& scope, AuthSession& session);
8675

8776
/// \brief Exchange a token for a scoped token using RFC 8693 Token Exchange.
88-
///
89-
/// Sends a POST request with form-encoded body to the token endpoint:
90-
/// grant_type=urn:ietf:params:oauth:grant-type:token-exchange
91-
/// &subject_token=...&subject_token_type=...&scope=...
92-
///
93-
/// Used by TableSession and ContextualSession to obtain table/context-specific
94-
/// tokens from a parent session's access token.
95-
///
96-
/// \param client HTTP client to use for the request.
97-
/// \param token_endpoint Full URL of the OAuth2 token endpoint.
98-
/// \param subject_token The access token to exchange.
99-
/// \param subject_token_type Token type URI (typically
100-
/// "urn:ietf:params:oauth:token-type:access_token").
101-
/// \param scope OAuth2 scope to request for the exchanged token.
102-
/// \param session Auth session for the request.
103-
/// \return A new token response with a scoped access_token, or an error.
10477
ICEBERG_REST_EXPORT Result<OAuthTokenResponse> ExchangeToken(
10578
HttpClient& client, const std::string& token_endpoint,
10679
const std::string& subject_token, const std::string& subject_token_type,

0 commit comments

Comments
 (0)