OAuth C++ Libraries
Authentication Library
OAuth C++ Libraries
Overview
OAuth 2.0 authentication libraries for C++ applications, with Google Cloud C++ OAuth2 Library and liboauth2 (OpenIDC) being the primary choices.
Details
C++ OAuth 2.0 implementation offers multiple library options. The most mature solution is the Google Cloud C++ OAuth2 Library, which specializes in Google services integration and provides simple authentication flows leveraging Application Default Credentials (ADC). This library is designed around the oauth2::AccessTokenGenerator interface and is continuously maintained.
Another major option is liboauth2 (OpenIDC), a generic C library for OAuth 2.0 and OpenID Connect implementation. It can build both servers and clients and is suitable for creating web server plugins. It serves as the foundation for mod_auth_openidc and offers commercial support.
Other options include oauth2cpp (GitHub - bschramke/oauth2cpp), which provides RFC 6749-compliant authorization code grant implementation but is still in development. POCO C++ Libraries also include basic OAuth credential classes. Qt 5.8 and later support OAuth 1.0 and 2.0 through the QtNetworkAuthentication module.
These libraries are used in various applications including enterprise applications, cloud service integration, and API access management. The choice depends on the platform used, services to integrate, and required features.
Pros and Cons
Pros
- High Performance: Fast authentication processing leveraging C++ native performance
- Enterprise Ready: Proven stability and track record in large-scale systems
- Google Integration: Seamless Google API integration through Google Cloud C++ Library
- Standards Compliance: Full compliance with RFC 6749 and OpenID Connect specifications
- Commercial Support: Commercial support available for liboauth2
- Web Server Integration: Web server plugin support through mod_auth_openidc integration
Cons
- Learning Curve: Requires deep understanding of C++ and OAuth 2.0 specifications
- Limited Documentation: Some libraries lack comprehensive documentation
- Complexity: Implementation complexity due to low-level API operations
- Platform Dependency: Platform-specific implementation may be required
- Memory Management: Responsibility for C++-specific memory management
- Development Speed: May be slower development compared to other languages
Key Links
- Google Cloud C++ OAuth2 Reference
- Google APIs Client Library for C++
- liboauth2 GitHub Repository
- OAuth2cpp GitHub Repository
- Qt Network Authentication
- POCO C++ Libraries OAuth
- RFC 6749 - OAuth 2.0 Authorization Framework
Code Examples
Google Cloud C++ OAuth2 Basic Implementation
#include "google/cloud/oauth2/access_token_generator.h"
#include "google/cloud/credentials.h"
#include <iostream>
#include <memory>
class OAuth2Client {
private:
std::unique_ptr<google::cloud::oauth2::AccessTokenGenerator> generator_;
public:
OAuth2Client() {
// Use Application Default Credentials
auto credentials = google::cloud::MakeGoogleDefaultCredentials();
if (!credentials) {
throw std::runtime_error("Failed to create default credentials");
}
generator_ = google::cloud::oauth2::MakeAccessTokenGenerator(*credentials);
}
std::string getAccessToken() {
auto token = generator_->GetToken();
if (!token) {
throw std::runtime_error("Failed to get access token: " + token.status().message());
}
return token->token;
}
bool isTokenExpired(const std::string& token) {
auto current_token = generator_->GetToken();
if (!current_token) return true;
auto expiry = current_token->expiration;
auto now = std::chrono::system_clock::now();
return expiry <= now;
}
void makeAuthenticatedRequest(const std::string& url) {
try {
std::string token = getAccessToken();
// Set token in HTTP request header
std::cout << "Making request to: " << url << std::endl;
std::cout << "Authorization: Bearer " << token.substr(0, 20) << "..." << std::endl;
// Actual HTTP request implementation goes here
} catch (const std::exception& e) {
std::cerr << "Request failed: " << e.what() << std::endl;
throw;
}
}
};
int main() {
try {
OAuth2Client client;
// Execute authenticated API request
client.makeAuthenticatedRequest("https://api.example.com/data");
return 0;
} catch (const std::exception& e) {
std::cerr << "OAuth2 Client Error: " << e.what() << std::endl;
return 1;
}
}
Custom OAuth2 Credentials Provider
#include "google/cloud/oauth2/access_token_generator.h"
#include "google/cloud/credentials.h"
#include <json/json.h>
#include <curl/curl.h>
#include <memory>
class CustomOAuth2Provider {
private:
std::string client_id_;
std::string client_secret_;
std::string token_url_;
std::string refresh_token_;
struct HTTPResponse {
std::string data;
long response_code;
};
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, HTTPResponse* response) {
size_t total_size = size * nmemb;
response->data.append(static_cast<char*>(contents), total_size);
return total_size;
}
public:
CustomOAuth2Provider(const std::string& client_id,
const std::string& client_secret,
const std::string& token_url)
: client_id_(client_id), client_secret_(client_secret), token_url_(token_url) {}
struct TokenResponse {
std::string access_token;
std::string refresh_token;
int expires_in;
std::string token_type;
};
TokenResponse exchangeAuthorizationCode(const std::string& auth_code,
const std::string& redirect_uri) {
CURL* curl = curl_easy_init();
if (!curl) {
throw std::runtime_error("Failed to initialize CURL");
}
HTTPResponse response;
// Prepare POST data
std::string post_data = "grant_type=authorization_code"
"&client_id=" + urlEncode(client_id_) +
"&client_secret=" + urlEncode(client_secret_) +
"&code=" + urlEncode(auth_code) +
"&redirect_uri=" + urlEncode(redirect_uri);
// Configure CURL
curl_easy_setopt(curl, CURLOPT_URL, token_url_.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
CURLcode res = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response.response_code);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
throw std::runtime_error("CURL request failed: " + std::string(curl_easy_strerror(res)));
}
if (response.response_code != 200) {
throw std::runtime_error("Token exchange failed. HTTP " + std::to_string(response.response_code) +
": " + response.data);
}
return parseTokenResponse(response.data);
}
TokenResponse refreshAccessToken(const std::string& refresh_token) {
CURL* curl = curl_easy_init();
if (!curl) {
throw std::runtime_error("Failed to initialize CURL");
}
HTTPResponse response;
std::string post_data = "grant_type=refresh_token"
"&client_id=" + urlEncode(client_id_) +
"&client_secret=" + urlEncode(client_secret_) +
"&refresh_token=" + urlEncode(refresh_token);
curl_easy_setopt(curl, CURLOPT_URL, token_url_.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
CURLcode res = curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response.response_code);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
if (res != CURLE_OK) {
throw std::runtime_error("CURL request failed: " + std::string(curl_easy_strerror(res)));
}
if (response.response_code != 200) {
throw std::runtime_error("Token refresh failed. HTTP " + std::to_string(response.response_code) +
": " + response.data);
}
return parseTokenResponse(response.data);
}
private:
std::string urlEncode(const std::string& value) {
CURL* curl = curl_easy_init();
if (!curl) return value;
char* encoded = curl_easy_escape(curl, value.c_str(), value.length());
if (!encoded) {
curl_easy_cleanup(curl);
return value;
}
std::string result(encoded);
curl_free(encoded);
curl_easy_cleanup(curl);
return result;
}
TokenResponse parseTokenResponse(const std::string& json_response) {
Json::Value root;
Json::Reader reader;
if (!reader.parse(json_response, root)) {
throw std::runtime_error("Failed to parse JSON response");
}
TokenResponse token;
token.access_token = root.get("access_token", "").asString();
token.refresh_token = root.get("refresh_token", "").asString();
token.expires_in = root.get("expires_in", 3600).asInt();
token.token_type = root.get("token_type", "Bearer").asString();
if (token.access_token.empty()) {
throw std::runtime_error("No access token in response");
}
return token;
}
};
// Usage example
int main() {
try {
CustomOAuth2Provider provider(
"your-client-id",
"your-client-secret",
"https://oauth.example.com/token"
);
// Exchange authorization code for access token
std::string auth_code = "received-authorization-code";
std::string redirect_uri = "https://your-app.com/callback";
auto token_response = provider.exchangeAuthorizationCode(auth_code, redirect_uri);
std::cout << "Access Token: " << token_response.access_token.substr(0, 20) << "..." << std::endl;
std::cout << "Expires in: " << token_response.expires_in << " seconds" << std::endl;
// Refresh access token using refresh token
if (!token_response.refresh_token.empty()) {
auto refreshed = provider.refreshAccessToken(token_response.refresh_token);
std::cout << "Refreshed Token: " << refreshed.access_token.substr(0, 20) << "..." << std::endl;
}
return 0;
} catch (const std::exception& e) {
std::cerr << "OAuth2 Error: " << e.what() << std::endl;
return 1;
}
}
Qt NetworkAuth OAuth2 Implementation
#include <QApplication>
#include <QOAuth2AuthorizationCodeFlow>
#include <QDesktopServices>
#include <QUrlQuery>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <iostream>
class QtOAuth2Client : public QObject {
Q_OBJECT
private:
QOAuth2AuthorizationCodeFlow* oauth2_;
QString access_token_;
public:
QtOAuth2Client(QObject* parent = nullptr) : QObject(parent) {
oauth2_ = new QOAuth2AuthorizationCodeFlow(this);
// OAuth2 configuration
oauth2_->setScope("read write");
oauth2_->setClientIdentifier("your-client-id");
oauth2_->setClientIdentifierSharedKey("your-client-secret");
oauth2_->setAuthorizationUrl(QUrl("https://oauth.example.com/authorize"));
oauth2_->setAccessTokenUrl(QUrl("https://oauth.example.com/token"));
// Connect signals
connect(oauth2_, &QOAuth2AuthorizationCodeFlow::statusChanged,
this, &QtOAuth2Client::onStatusChanged);
connect(oauth2_, &QOAuth2AuthorizationCodeFlow::granted,
this, &QtOAuth2Client::onGranted);
connect(oauth2_, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser,
&QDesktopServices::openUrl);
}
public slots:
void authenticate() {
oauth2_->grant();
}
void makeApiRequest(const QString& url) {
if (access_token_.isEmpty()) {
std::cerr << "No access token available" << std::endl;
return;
}
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
// Set access token in Authorization header
QString auth_header = "Bearer " + access_token_;
request.setRawHeader("Authorization", auth_header.toUtf8());
QNetworkReply* reply = oauth2_->networkAccessManager()->get(request);
connect(reply, &QNetworkReply::finished, [reply, this]() {
if (reply->error() == QNetworkReply::NoError) {
QByteArray data = reply->readAll();
QJsonDocument doc = QJsonDocument::fromJson(data);
std::cout << "API Response: " << doc.toJson().toStdString() << std::endl;
} else {
std::cerr << "API Request failed: " << reply->errorString().toStdString() << std::endl;
}
reply->deleteLater();
});
}
private slots:
void onStatusChanged(QAbstractOAuth::Status status) {
switch (status) {
case QAbstractOAuth::Status::NotAuthenticated:
std::cout << "Not authenticated" << std::endl;
break;
case QAbstractOAuth::Status::TemporaryCredentialsReceived:
std::cout << "Temporary credentials received" << std::endl;
break;
case QAbstractOAuth::Status::Granted:
std::cout << "Access granted" << std::endl;
break;
case QAbstractOAuth::Status::RefreshingToken:
std::cout << "Refreshing token" << std::endl;
break;
}
}
void onGranted() {
access_token_ = oauth2_->token();
std::cout << "Authentication successful!" << std::endl;
std::cout << "Access Token: " << access_token_.left(20).toStdString() << "..." << std::endl;
// Example API request
makeApiRequest("https://api.example.com/user");
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QtOAuth2Client client;
// Start authentication
client.authenticate();
return app.exec();
}
#include "main.moc"
PKCE-Enabled OAuth2 Implementation
#include <iostream>
#include <string>
#include <random>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
class PKCEOAuth2Client {
private:
std::string code_verifier_;
std::string code_challenge_;
std::string generateRandomString(size_t length) {
const std::string charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dist(0, charset.size() - 1);
std::string result;
result.reserve(length);
for (size_t i = 0; i < length; ++i) {
result += charset[dist(gen)];
}
return result;
}
std::string base64UrlEncode(const std::vector<unsigned char>& data) {
BIO* bio = BIO_new(BIO_s_mem());
BIO* b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bio = BIO_push(b64, bio);
BIO_write(bio, data.data(), data.size());
BIO_flush(bio);
BUF_MEM* bufferPtr;
BIO_get_mem_ptr(bio, &bufferPtr);
std::string result(bufferPtr->data, bufferPtr->length);
BIO_free_all(bio);
// Character replacement for Base64URL encoding
for (char& c : result) {
if (c == '+') c = '-';
else if (c == '/') c = '_';
}
// Remove padding
result.erase(result.find_last_not_of('=') + 1);
return result;
}
std::string generateCodeChallenge(const std::string& verifier) {
// Calculate SHA256 hash
std::vector<unsigned char> hash(SHA256_DIGEST_LENGTH);
SHA256(reinterpret_cast<const unsigned char*>(verifier.c_str()),
verifier.length(), hash.data());
// Base64URL encode
return base64UrlEncode(hash);
}
public:
PKCEOAuth2Client() {
// Generate code verifier (43-128 character random string)
code_verifier_ = generateRandomString(128);
// Generate code challenge (SHA256 hash + Base64URL encode)
code_challenge_ = generateCodeChallenge(code_verifier_);
}
std::string getAuthorizationUrl(const std::string& client_id,
const std::string& redirect_uri,
const std::string& scope,
const std::string& state) {
std::string auth_url = "https://oauth.example.com/authorize"
"?response_type=code"
"&client_id=" + urlEncode(client_id) +
"&redirect_uri=" + urlEncode(redirect_uri) +
"&scope=" + urlEncode(scope) +
"&state=" + urlEncode(state) +
"&code_challenge=" + urlEncode(code_challenge_) +
"&code_challenge_method=S256";
return auth_url;
}
struct TokenResponse {
std::string access_token;
std::string refresh_token;
int expires_in;
std::string token_type;
std::string scope;
};
TokenResponse exchangeCodeForToken(const std::string& client_id,
const std::string& authorization_code,
const std::string& redirect_uri) {
std::string post_data = "grant_type=authorization_code"
"&client_id=" + urlEncode(client_id) +
"&code=" + urlEncode(authorization_code) +
"&redirect_uri=" + urlEncode(redirect_uri) +
"&code_verifier=" + urlEncode(code_verifier_);
// Execute HTTP request (implementation omitted, use libcurl in actual implementation)
std::string response_json = makeHttpPost("https://oauth.example.com/token", post_data);
return parseTokenResponse(response_json);
}
void demonstrateFlow() {
std::string client_id = "your-public-client-id";
std::string redirect_uri = "https://your-app.com/callback";
std::string scope = "read write";
std::string state = generateRandomString(32);
// 1. Generate authorization URL
std::string auth_url = getAuthorizationUrl(client_id, redirect_uri, scope, state);
std::cout << "1. Generated authorization URL:" << std::endl;
std::cout << auth_url << std::endl << std::endl;
std::cout << "2. PKCE parameters:" << std::endl;
std::cout << "Code Verifier: " << code_verifier_ << std::endl;
std::cout << "Code Challenge: " << code_challenge_ << std::endl;
std::cout << "Code Challenge Method: S256" << std::endl << std::endl;
std::cout << "3. Redirect user to authorization URL to obtain authorization code" << std::endl;
std::cout << "4. Call exchangeCodeForToken() with the obtained authorization code" << std::endl;
}
private:
std::string urlEncode(const std::string& value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (char c : value) {
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
} else {
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int(static_cast<unsigned char>(c));
escaped << std::nouppercase;
}
}
return escaped.str();
}
std::string makeHttpPost(const std::string& url, const std::string& data) {
// Use libcurl or equivalent HTTP library in actual implementation
// Return dummy response here
return R"({
"access_token": "example_access_token_12345",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "example_refresh_token_67890",
"scope": "read write"
})";
}
TokenResponse parseTokenResponse(const std::string& json) {
TokenResponse response;
// Use JSON parsing library in actual implementation
// Set fixed values as simple example here
response.access_token = "example_access_token_12345";
response.token_type = "Bearer";
response.expires_in = 3600;
response.refresh_token = "example_refresh_token_67890";
response.scope = "read write";
return response;
}
};
int main() {
try {
PKCEOAuth2Client pkce_client;
std::cout << "=== PKCE OAuth2 Client Demo ===" << std::endl << std::endl;
// Demonstrate PKCE flow
pkce_client.demonstrateFlow();
return 0;
} catch (const std::exception& e) {
std::cerr << "PKCE OAuth2 Error: " << e.what() << std::endl;
return 1;
}
}
Error Handling and Logging
#include <iostream>
#include <fstream>
#include <chrono>
#include <iomanip>
#include <sstream>
class OAuth2Logger {
private:
std::ofstream log_file_;
std::string getCurrentTimestamp() {
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S");
return ss.str();
}
public:
OAuth2Logger(const std::string& log_file_path = "oauth2_client.log")
: log_file_(log_file_path, std::ios::app) {}
enum class LogLevel {
DEBUG,
INFO,
WARNING,
ERROR
};
void log(LogLevel level, const std::string& message) {
std::string level_str;
switch (level) {
case LogLevel::DEBUG: level_str = "DEBUG"; break;
case LogLevel::INFO: level_str = "INFO"; break;
case LogLevel::WARNING: level_str = "WARNING"; break;
case LogLevel::ERROR: level_str = "ERROR"; break;
}
std::string log_entry = "[" + getCurrentTimestamp() + "] " +
level_str + ": " + message;
log_file_ << log_entry << std::endl;
log_file_.flush();
// Also output to console (errors and warnings only)
if (level == LogLevel::ERROR || level == LogLevel::WARNING) {
std::cerr << log_entry << std::endl;
}
}
};
class RobustOAuth2Client {
private:
OAuth2Logger logger_;
std::string client_id_;
std::string client_secret_;
std::string token_url_;
std::string current_token_;
std::chrono::system_clock::time_point token_expiry_;
int max_retries_;
int retry_delay_ms_;
public:
RobustOAuth2Client(const std::string& client_id,
const std::string& client_secret,
const std::string& token_url,
int max_retries = 3,
int retry_delay_ms = 1000)
: client_id_(client_id), client_secret_(client_secret),
token_url_(token_url), max_retries_(max_retries),
retry_delay_ms_(retry_delay_ms) {
logger_.log(OAuth2Logger::LogLevel::INFO, "OAuth2 Client initialized");
}
enum class OAuth2Error {
NETWORK_ERROR,
INVALID_CLIENT,
INVALID_GRANT,
INVALID_REQUEST,
UNAUTHORIZED_CLIENT,
UNSUPPORTED_GRANT_TYPE,
INVALID_SCOPE,
RATE_LIMITED,
SERVER_ERROR,
UNKNOWN_ERROR
};
class OAuth2Exception : public std::exception {
private:
OAuth2Error error_code_;
std::string message_;
int http_status_;
public:
OAuth2Exception(OAuth2Error error_code, const std::string& message, int http_status = 0)
: error_code_(error_code), message_(message), http_status_(http_status) {}
const char* what() const noexcept override {
return message_.c_str();
}
OAuth2Error getErrorCode() const { return error_code_; }
int getHttpStatus() const { return http_status_; }
};
std::string getAccessTokenWithRetry() {
if (isTokenValid()) {
return current_token_;
}
OAuth2Exception last_exception(OAuth2Error::UNKNOWN_ERROR, "Unknown error");
for (int attempt = 1; attempt <= max_retries_; ++attempt) {
try {
logger_.log(OAuth2Logger::LogLevel::INFO,
"Attempting token request (attempt " + std::to_string(attempt) + "/" +
std::to_string(max_retries_) + ")");
auto token_response = requestAccessToken();
current_token_ = token_response.access_token;
// Set token expiration time
auto now = std::chrono::system_clock::now();
token_expiry_ = now + std::chrono::seconds(token_response.expires_in - 60); // 60 second margin
logger_.log(OAuth2Logger::LogLevel::INFO, "Access token obtained successfully");
return current_token_;
} catch (const OAuth2Exception& e) {
last_exception = e;
logger_.log(OAuth2Logger::LogLevel::ERROR,
"Token request failed (attempt " + std::to_string(attempt) + "): " + e.what());
// Check if error is retryable
if (!isRetryableError(e.getErrorCode())) {
logger_.log(OAuth2Logger::LogLevel::ERROR, "Non-retryable error, aborting");
throw;
}
// Special wait time for rate limiting
if (e.getErrorCode() == OAuth2Error::RATE_LIMITED) {
int wait_time = extractRetryAfter(e.what());
if (wait_time > 0) {
logger_.log(OAuth2Logger::LogLevel::INFO,
"Rate limited, waiting " + std::to_string(wait_time) + " seconds");
std::this_thread::sleep_for(std::chrono::seconds(wait_time));
continue;
}
}
// Normal retry wait
if (attempt < max_retries_) {
int wait_time = retry_delay_ms_ * attempt;
logger_.log(OAuth2Logger::LogLevel::INFO,
"Waiting " + std::to_string(wait_time) + "ms before retry");
std::this_thread::sleep_for(std::chrono::milliseconds(wait_time));
}
}
}
logger_.log(OAuth2Logger::LogLevel::ERROR,
"Failed to obtain access token after " + std::to_string(max_retries_) + " attempts");
throw last_exception;
}
bool makeSecureApiCall(const std::string& url, const std::string& method = "GET") {
try {
std::string token = getAccessTokenWithRetry();
logger_.log(OAuth2Logger::LogLevel::INFO,
"Making " + method + " request to: " + url);
// Execute HTTP request (implementation omitted)
bool success = executeHttpRequest(url, method, token);
if (success) {
logger_.log(OAuth2Logger::LogLevel::INFO, "API call successful");
} else {
logger_.log(OAuth2Logger::LogLevel::ERROR, "API call failed");
}
return success;
} catch (const OAuth2Exception& e) {
logger_.log(OAuth2Logger::LogLevel::ERROR,
"API call failed due to OAuth2 error: " + std::string(e.what()));
return false;
} catch (const std::exception& e) {
logger_.log(OAuth2Logger::LogLevel::ERROR,
"API call failed due to unexpected error: " + std::string(e.what()));
return false;
}
}
private:
struct TokenResponse {
std::string access_token;
std::string token_type;
int expires_in;
};
bool isTokenValid() {
if (current_token_.empty()) return false;
auto now = std::chrono::system_clock::now();
return now < token_expiry_;
}
bool isRetryableError(OAuth2Error error) {
switch (error) {
case OAuth2Error::NETWORK_ERROR:
case OAuth2Error::RATE_LIMITED:
case OAuth2Error::SERVER_ERROR:
return true;
default:
return false;
}
}
int extractRetryAfter(const std::string& error_message) {
// Extract Retry-After value from error message
// Implementation omitted, actually extract from HTTP headers
return 0;
}
TokenResponse requestAccessToken() {
// Request access token with Client Credentials flow
// Execute HTTP POST request in actual implementation
// Demo implementation
TokenResponse response;
response.access_token = "demo_access_token_" + std::to_string(std::time(nullptr));
response.token_type = "Bearer";
response.expires_in = 3600;
return response;
}
bool executeHttpRequest(const std::string& url, const std::string& method, const std::string& token) {
// Execute actual HTTP request
// Use libcurl etc. to set Bearer token in Authorization header
// Demo implementation
return true;
}
};
int main() {
try {
RobustOAuth2Client client(
"your-client-id",
"your-client-secret",
"https://oauth.example.com/token",
3, // max_retries
2000 // retry_delay_ms
);
// Secure API call
bool success = client.makeSecureApiCall("https://api.example.com/secure-data");
if (success) {
std::cout << "API call completed successfully" << std::endl;
} else {
std::cout << "API call failed" << std::endl;
}
return 0;
} catch (const std::exception& e) {
std::cerr << "Application error: " << e.what() << std::endl;
return 1;
}
}