algotradelib 0.0.0.9000
C++ header-only library for algorithmic trading
Loading...
Searching...
No Matches
auth.hpp
1#pragma once
2
3#include "./config.hpp"
4#include "./network.hpp"
5
6#include <mutex>
7
8namespace algotradelib {
9namespace kis {
10
11class KisAuth;
12
19class KisAuth {
20public:
27 KisAuth(net::io_context& ioc, ssl::context& ctx, const KisConfig& config)
28 : ioc_(ioc), ctx_(ctx), req_(config) {}
29
31 virtual ~KisAuth() = default;
32
40 std::string accessToken() {
41 std::lock_guard<std::mutex> lock(mtx_);
42 if (!rest_resp_.valid()) {
43 refresh();
44 }
45 return rest_resp_.access_token_;
46 }
47
54 std::string accessWebsocket() {
55 std::lock_guard<std::mutex> lock(mtx_);
56 if (!ws_resp_.valid()) {
57 refreshWebsocket();
58 }
59 return ws_resp_.approval_key_;
60 }
61
62private:
63 net::io_context& ioc_;
64 ssl::context& ctx_;
65 KisConfig req_;
66 KisRest rest_resp_;
67 KisWebsocket ws_resp_;
68 std::mutex mtx_;
69
70 void refresh() {
71 const std::string jsonbody = req_.to_jsonbody();
72 KisHttpClient rest(ioc_, ctx_, req_.rest_host(), req_.rest_port());
73 auto response = rest.post("/oauth2/tokenP", jsonbody, {{"content-type", "application/json"}});
74 if (response.result_int() < 200 || response.result_int() >= 300) {
75 throw std::runtime_error(
76 "Token authentication failed with HTTP status " + std::to_string(response.result_int())
77 );
78 }
79 const std::string resp = std::move(response.body());
80 boost::system::error_code ec;
81 const auto jv = json::parse(resp, ec);
82 // const auto* doc = (!ec && jv.is_object()) ? &jv.as_object() : nullptr;
83 // if (!doc || !doc->contains("access_token")) {
84 // throw std::runtime_error("Token authentication failed: " + resp);
85 // }
86 // rest_resp_.access_token_ = doc->at("access_token").as_string().c_str();
87 // rest_resp_.expires_in_ = doc->contains("expires_in") ? doc->at("expires_in").as_int64() :
88 // 86400; rest_resp_.access_token_expired_ = doc->contains("access_token_token_expired") ?
89 // parse_expiry(doc->at("access_token_token_expired").as_string().c_str()) :
90 // std::chrono::system_clock::now() + std::chrono::seconds(86400);
91 if (ec || !jv.is_object()) {
92 // Not the body: a token reply that did not parse may still hold the token.
93 throw std::runtime_error(
94 "Token authentication failed: the reply is not a JSON object (" + std::to_string(resp.size()) + " bytes)"
95 );
96 }
97 rest_resp_.from_json(jv.as_object());
98 }
99
100 void refreshWebsocket() {
101 const std::string jsonbody = req_.ws_to_jsonbody();
102 KisHttpClient rest(ioc_, ctx_, req_.rest_host(), req_.rest_port());
103 // _base_headers_ws = {
104 // "content-type": "utf-8",
105 // }
106 auto response = rest.post("/oauth2/Approval", jsonbody, {{"content-type", "utf-8"}});
107 if (response.result_int() < 200 || response.result_int() >= 300) {
108 throw std::runtime_error(
109 "WebSocket authentication failed with HTTP status " + std::to_string(response.result_int())
110 );
111 }
112 const std::string resp = std::move(response.body());
113 boost::system::error_code ec;
114 const auto jv = json::parse(resp, ec);
115 // const auto* doc = (!ec && jv.is_object()) ? &jv.as_object() : nullptr;
116 // if (!doc || !doc->contains("approval_key")) {
117 // throw std::runtime_error("WS approval key authentication failed: " + resp);
118 // }
119 // ws_resp_.approval_key = doc->at("approval_key").as_string().c_str();
120 // ws_resp_.last_auth_time = std::chrono::system_clock::now();
121 if (ec || !jv.is_object()) {
122 // Not the body: an approval reply that did not parse may still hold the key.
123 throw std::runtime_error(
124 "WebSocket authentication failed: the reply is not a JSON object (" + std::to_string(resp.size()) +
125 " bytes)"
126 );
127 }
128 ws_resp_.from_json(jv.as_object());
129 }
130};
131
132} // namespace kis
133} // namespace algotradelib
Obtains and caches KIS access tokens and WebSocket approval keys with blocking requests; thread-safe.
Definition auth.hpp:19
virtual ~KisAuth()=default
Destroys the wrapper.
std::string accessWebsocket()
Returns a WebSocket approval key, requesting a new one if none is held or it is a day old.
Definition auth.hpp:54
KisAuth(net::io_context &ioc, ssl::context &ctx, const KisConfig &config)
Constructs the wrapper.
Definition auth.hpp:27
std::string accessToken()
Returns a REST access token, requesting a new one if none is held or it expires within five minutes.
Definition auth.hpp:40
std::string to_jsonbody() const
Builds a JSON token-request body (grant type, key and secret under the broker's field names).
Definition oauth.hpp:75
The Korea Investment & Securities (KIS) Open API client.
Definition auth.hpp:9
network::HttpClient KisHttpClient
The blocking HTTP client KisAuth uses.
Definition network.hpp:9
The library: broker-neutral types (core), and the modules below.
KIS credentials (app key and secret), demo or real account, and the market-data tape.
Definition config.hpp:90
const char * rest_port() const noexcept
Returns the REST port for the environment.
Definition config.hpp:238
const char * rest_host() const noexcept
Returns the REST host for the environment.
Definition config.hpp:230
A KIS REST access token and its expiry.
Definition config.hpp:263
A KIS WebSocket approval key and when it was issued.
Definition config.hpp:309