Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Client.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Frameworks_Auth_OAuth_Client_h_
5#define _Stroika_Frameworks_Auth_OAuth_Client_h_ 1
6
7#include "Stroika/Frameworks/StroikaPreComp.h"
8
10#include "Stroika/Foundation/Common/Common.h"
11#include "Stroika/Foundation/Common/GUID.h"
12#include "Stroika/Foundation/Containers/KeyedCollection.h"
13#include "Stroika/Foundation/Containers/Sequence.h"
14#include "Stroika/Foundation/DataExchange/ObjectVariantMapper.h"
17
19
20/**
21 * \file
22 *
23 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
24 */
25
26namespace Stroika::Frameworks::Auth::OAuth {
27
28 using namespace Stroika::Foundation;
29
31 using Containers::Set;
33 using IO::Network::URI;
34 using Time::DateTime;
35
37
38 /**
39 * MEANT to be provider independent, but best docs I've found so far...
40 *
41 * https://developers.google.com/identity/protocols/oauth2/web-server#httprest_3
42 */
43 struct TokenRequest {
44 /**
45 * The client ID obtained from the Cloud Console Clients page (https://console.cloud.google.com/auth/clients).
46 */
48
49 /**
50 * The authorization code returned from the request (https://developers.google.com/identity/protocols/oauth2/web-server#httprest_1)
51 *
52 * \note refresh_token and code are mutually exclusive (not using variant cuz same type and no name)
53 *
54 * implies grant_type: authorization_code
55 */
56 optional<String> code;
57
58 /**
59 * \note refresh_token and code are mutually exclusive (not using variant cuz same type and no name)
60 *
61 * implies grant_type: refresh_token
62 */
63 optional<String> refresh_token;
64
65#if 0
66 /**
67 * \brief set to 'authorization_code' when exchanging authorization code for access token
68 *
69 * https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1
70 */
71 String grant_type{"authorization_code"sv};
72#endif
73
74 /**
75 * The client secret obtained from the Cloud Console Clients page (https://console.cloud.google.com/auth/clients).
76 * It is also often found in ClientConfiguration::fClientSecret
77 */
78 optional<String> client_secret;
79
80 /**
81 * One of the redirect URIs listed for your project in the Cloud Console Clients page (https://console.cloud.google.com/auth/clients) for the given client_id.
82 * Needed for most flows, but not all.
83 */
84 optional<URI> redirect_uri;
85
86 /**
87 * WAG - FIND DOCS ON THIS---
88 * \note only applies to
89 */
90 optional<String> code_verifier;
91
92 nonvirtual String ToString () const;
93
94 nonvirtual TypedBLOB ToWireFormat () const;
95 static TokenRequest FromWireFormat (const TypedBLOB& src);
96
97 static const ObjectVariantMapper kMapper;
98 };
99
100 /**
101 * MEANT to be provider independent, but best docs I've found so far...
102 *
103 * https://developers.google.com/identity/protocols/oauth2/web-server#exchange-authorization-code
104 */
106 /**
107 * https://datatracker.ietf.org/doc/html/rfc6749#section-1.4
108 */
110
111 /**
112 * OAuth uses expires_in, but we convert to an expires_at since better to track (in UTC)
113 */
114 DateTime expires_at = DateTime::Now ();
115
116 Set<String> scope;
117
118 /**
119 * https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
120 */
121 optional<String> refresh_token;
122
123 /**
124 */
125 optional<String> id_token;
126
127 /**
128 */
129 optional<String> token_type;
130
131 nonvirtual String ToString () const;
132
133 nonvirtual TypedBLOB ToWireFormat () const;
134 static TokenResponse FromWireFormat (const TypedBLOB& src);
135
136 static const ObjectVariantMapper kMapper;
137 };
138
139 /**
140 */
141 struct TokenRevocationRequest {
142 String access_token;
143 optional<String> refresh_token;
144 optional<String> client_id;
145 optional<String> client_secret;
146
147 nonvirtual String ToString () const;
148
149 nonvirtual TypedBLOB ToWireFormat () const;
150
151 static const ObjectVariantMapper kMapper;
152 };
153
154 /**
155 */
156 struct UserInfo {
157
158 /**
159 */
160 optional<String> name;
161
162 /**
163 */
164 optional<String> given_name;
165
166 /**
167 */
168 optional<String> family_name;
169
170 /**
171 */
172 optional<String> email;
173
174 /**
175 * image of user (thumbnail)
176 */
177 optional<URI> picture;
178
179 nonvirtual String ToString () const;
180
181 static UserInfo FromWireFormat (const TypedBLOB& src);
182
183 static const ObjectVariantMapper kMapper;
184 };
185
186 /**
187 * \brief simple wrapper on IO::Network::Transfer to do fetching (more configurability to do)
188 */
189 class Fetcher {
190 public:
191 Fetcher () = delete;
192 Fetcher (const Fetcher&) = default;
193 Fetcher (const ProviderConfiguration& providerConfiguration);
194
195 public:
196 /**
197 * https://developers.google.com/identity/protocols/oauth2/web-server#exchange-authorization-code
198 * https://developers.google.com/identity/protocols/oauth2/web-server#offline
199 *
200 * This can be used to convert EITHER an authorization_code (code parameter) or a refresh_token
201 * to a new access_code (and other TokenResponse info).
202 *
203 * \note - confusingly - despite docs above to the contrary, if you are not getting a refresh_token back it could
204 * be because google doesn't return it except on the first get token call
205 * (https://stackoverflow.com/questions/10827920/not-receiving-google-oauth-refresh-token)
206 */
207 nonvirtual TokenResponse GetToken (const TokenRequest& tr) const;
208
209 public:
210 /**
211 * Try to revoke the given refresh/access tokens. If no URI found in the ProviderConfiguration, its assumed the provider
212 * doesn't support this, and nothing todo. If an error occurs (say because of bad or missing client_id, or client_secret or already revoked?)
213 * an exception will be reported.
214 *
215 * \see https://datatracker.ietf.org/doc/html/rfc7009 (but this is woefully insufficient/incomplete/NOT what I followed)
216 * \see https://github.com/openid/AppAuth-JS/blob/master/src/revoke_token_request.ts - really got impl from here
217 */
218 nonvirtual void RevokeTokens (const TokenRevocationRequest& tr) const;
219
220 public:
221 /**
222 * curl -v -H "Authorization: Bearer ddd" https://www.googleapis.com/oauth2/v3/userinfo
223 *
224 * @todo FIND DOCS FOR THIS - try docs on https://accounts.google.com/.well-known/openid-configuration
225 */
226 nonvirtual UserInfo GetUserInfo (const String& accessToken) const;
227
228 private:
229 const ProviderConfiguration fProviderConfiguration_;
230 };
231
232}
233
234/*
235 ********************************************************************************
236 ***************************** Implementation Details ***************************
237 ********************************************************************************
238 */
239#include "Client.inl"
240
241#endif /*_Stroika_Frameworks_Auth_OAuth_Client_h_*/
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
Definition Set.h:105
ObjectVariantMapper can be used to map C++ types to and from variant-union types, which can be transp...
TypedBLOB is a named tuple<Memory::BLOB, optional<InternetMediaType>> - with friendlier names,...
Definition TypedBLOB.h:48
simple wrapper on IO::Network::Transfer to do fetching (more configurability to do)
Definition Client.h:189
nonvirtual UserInfo GetUserInfo(const String &accessToken) const
Definition Client.cpp:379
nonvirtual TokenResponse GetToken(const TokenRequest &tr) const
Definition Client.cpp:345
nonvirtual void RevokeTokens(const TokenRevocationRequest &tr) const
Definition Client.cpp:361
Track configuration data about stuff that differentiates different OAuth providers - what URLs to use...