12#if DETWS_ENABLE_OAUTH2
28void put_raw(Buf &b,
const char *s)
41bool unreserved(
char c)
43 return (c >=
'A' && c <=
'Z') || (c >=
'a' && c <=
'z') || (c >=
'0' && c <=
'9') || c ==
'-' || c ==
'.' ||
48void put_enc(Buf &b,
const char *s)
52 unsigned char c = (
unsigned char)*s;
53 if (unreserved((
char)c))
77void put_param(Buf &b,
const char *key,
const char *val)
87 if (!b.ok || b.n >= b.cap)
94int detws_oauth2_build_code_request(
const char *code,
const char *redirect_uri,
const char *client_id,
95 const char *client_secret,
const char *code_verifier,
char *out,
size_t cap)
97 if (!code || !redirect_uri || !client_id || !out || cap == 0)
99 Buf b = {out, cap, 0,
true};
100 put_raw(b,
"grant_type=authorization_code");
101 put_param(b,
"code", code);
102 put_param(b,
"redirect_uri", redirect_uri);
103 put_param(b,
"client_id", client_id);
105 put_param(b,
"client_secret", client_secret);
107 put_param(b,
"code_verifier", code_verifier);
111int detws_oauth2_build_refresh_request(
const char *refresh_token,
const char *client_id,
const char *client_secret,
112 char *out,
size_t cap)
114 if (!refresh_token || !client_id || !out || cap == 0)
116 Buf b = {out, cap, 0,
true};
117 put_raw(b,
"grant_type=refresh_token");
118 put_param(b,
"refresh_token", refresh_token);
119 put_param(b,
"client_id", client_id);
121 put_param(b,
"client_secret", client_secret);
125bool detws_oauth2_parse_token_response(
const char *json, DetwsOAuth2Tokens *out)
129 out->access_token[0] =
'\0';
130 out->id_token[0] =
'\0';
131 out->refresh_token[0] =
'\0';
132 out->token_type[0] =
'\0';
135 if (!
json_get_str(json,
"access_token", out->access_token,
sizeof(out->access_token)))
137 json_get_str(json,
"id_token", out->id_token,
sizeof(out->id_token));
138 json_get_str(json,
"refresh_token", out->refresh_token,
sizeof(out->refresh_token));
139 json_get_str(json,
"token_type", out->token_type,
sizeof(out->token_type));
146#if DETWS_ENABLE_HTTP_CLIENT
157 char body[DETWS_OAUTH2_BODY_BUF];
158 char resp[DETWS_OAUTH2_RESP_BUF];
162int post_and_parse(Oauth2Ctx &c,
const char *token_url,
int body_len, DetwsOAuth2Tokens *out)
165 return (
int)DetwsOAuth2Result::DETWS_OAUTH2_ERR_BUILD;
167 int st = http_post(token_url,
"application/x-www-form-urlencoded", (
const uint8_t *)c.body, (
size_t)body_len, &r);
169 return (
int)DetwsOAuth2Result::DETWS_OAUTH2_ERR_TRANSPORT;
170 size_t k = r.body_len <
sizeof(c.resp) - 1 ? r.body_len : sizeof(c.resp) - 1;
172 memcpy(c.resp, r.body, k);
174 if (!detws_oauth2_parse_token_response(c.resp, out))
177 : (int)DetwsOAuth2Result::DETWS_OAUTH2_ERR_RESPONSE;
182int detws_oauth2_exchange_code(
const char *token_url,
const char *code,
const char *redirect_uri,
const char *client_id,
183 const char *client_secret,
const char *code_verifier, DetwsOAuth2Tokens *out)
185 int n = detws_oauth2_build_code_request(code, redirect_uri, client_id, client_secret, code_verifier, s_oauth.body,
186 sizeof(s_oauth.body));
187 return post_and_parse(s_oauth, token_url, n, out);
190int detws_oauth2_refresh(
const char *token_url,
const char *refresh_token,
const char *client_id,
191 const char *client_secret, DetwsOAuth2Tokens *out)
194 detws_oauth2_build_refresh_request(refresh_token, client_id, client_secret, s_oauth.body,
sizeof(s_oauth.body));
195 return post_and_parse(s_oauth, token_url, n, out);
Tiny no-stdlib hex encode / decode / nibble helpers (one shared copy).
char det_hex_digit(int nibble, bool upper=false)
Nibble 0..15 -> hex char (lowercase, or uppercase when upper).
Zero-heap outbound HTTP(S) client over raw lwIP (DETWS_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 (DETWS_ENABLE_OAUTH2).