17#if PC_ENABLE_HTTP_CLIENT
31void put_raw(Buf &b,
const char *s)
44bool unreserved(
char c)
46 return (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9') || c ==
'-' || c ==
'.' ||
51void put_enc(Buf &b,
const char *s)
55 unsigned char c = (
unsigned char)*s;
56 if (unreserved((
char)c))
80void put_param(Buf &b,
const char *key,
const char *val)
90 if (!b.ok || b.n >= b.cap)
102int pc_oauth2_build_code_request(
const char *code,
const char *redirect_uri,
const char *client_id,
103 const char *client_secret,
const char *code_verifier,
char *out,
size_t cap)
105 if (!code || !redirect_uri || !client_id || !out || cap == 0)
109 Buf b = {out, cap, 0,
true};
110 put_raw(b,
"grant_type=authorization_code");
111 put_param(b,
"code", code);
112 put_param(b,
"redirect_uri", redirect_uri);
113 put_param(b,
"client_id", client_id);
116 put_param(b,
"client_secret", client_secret);
120 put_param(b,
"code_verifier", code_verifier);
125int pc_oauth2_build_refresh_request(
const char *refresh_token,
const char *client_id,
const char *client_secret,
126 char *out,
size_t cap)
128 if (!refresh_token || !client_id || !out || cap == 0)
132 Buf b = {out, cap, 0,
true};
133 put_raw(b,
"grant_type=refresh_token");
134 put_param(b,
"refresh_token", refresh_token);
135 put_param(b,
"client_id", client_id);
138 put_param(b,
"client_secret", client_secret);
143bool pc_oauth2_parse_token_response(
const char *json, pc_o_auth2_tokens *out)
149 out->access_token[0] =
'\0';
150 out->id_token[0] =
'\0';
151 out->refresh_token[0] =
'\0';
152 out->token_type[0] =
'\0';
155 if (!
json_get_str(json,
"access_token", out->access_token,
sizeof(out->access_token)))
159 json_get_str(json,
"id_token", out->id_token,
sizeof(out->id_token));
160 json_get_str(json,
"refresh_token", out->refresh_token,
sizeof(out->refresh_token));
161 json_get_str(json,
"token_type", out->token_type,
sizeof(out->token_type));
170#if PC_ENABLE_HTTP_CLIENT
179 char body[PC_OAUTH2_BODY_BUF];
180 char resp[PC_OAUTH2_RESP_BUF];
184int post_and_parse(Oauth2Ctx &c,
const char *token_url,
int body_len, pc_o_auth2_tokens *out)
188 return (
int)pc_o_auth2_result::PC_OAUTH2_ERR_BUILD;
191 int st = http_post(token_url,
"application/x-www-form-urlencoded", (
const uint8_t *)c.body, (
size_t)body_len, &r);
194 return (
int)pc_o_auth2_result::PC_OAUTH2_ERR_TRANSPORT;
196 size_t k = r.body_len <
sizeof(c.resp) - 1 ? r.body_len : sizeof(c.resp) - 1;
199 memcpy(c.resp, r.body, k);
202 if (!pc_oauth2_parse_token_response(c.resp, out))
204 return st >= 400 ? st
205 : (int)pc_o_auth2_result::PC_OAUTH2_ERR_RESPONSE;
211int pc_oauth2_exchange_code(
const char *token_url,
const char *code,
const char *redirect_uri,
const char *client_id,
212 const char *client_secret,
const char *code_verifier, pc_o_auth2_tokens *out)
214 int n = pc_oauth2_build_code_request(code, redirect_uri, client_id, client_secret, code_verifier, s_oauth.body,
215 sizeof(s_oauth.body));
216 return post_and_parse(s_oauth, token_url, n, out);
219int pc_oauth2_refresh(
const char *token_url,
const char *refresh_token,
const char *client_id,
220 const char *client_secret, pc_o_auth2_tokens *out)
223 pc_oauth2_build_refresh_request(refresh_token, client_id, client_secret, s_oauth.body,
sizeof(s_oauth.body));
224 return post_and_parse(s_oauth, token_url, n, out);
Base-16 conversion between raw bytes and their ASCII digits.
char pc_hex_digit(uint8_t nibble, bool upper=false)
Low nibble of nibble as a hex character, uppercase when upper.
Zero-heap outbound HTTP(S) client over raw lwIP (PC_ENABLE_HTTP_CLIENT).
bool json_get_str(const char *json, const char *key, char *out, size_t out_cap)
Read a top-level string member from a JSON object body.
bool json_get_int(const char *json, const char *key, long *out)
Read a top-level integer member from a JSON object body.
Layer 6 (Presentation) - zero-heap JSON: a bounded writer and top-level reader.
OAuth2 token-endpoint client - authorization-code + refresh (PC_ENABLE_OAUTH2).