1 | // Copyright (C) 2017 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <qabstractoauth2.h> |
5 | #include <private/qabstractoauth2_p.h> |
6 | |
7 | #include <QtCore/qurl.h> |
8 | #include <QtCore/qurlquery.h> |
9 | #include <QtCore/qbytearray.h> |
10 | #include <QtCore/qmessageauthenticationcode.h> |
11 | |
12 | #include <QtNetwork/qnetworkreply.h> |
13 | #include <QtNetwork/qnetworkrequest.h> |
14 | #include <QtNetwork/qnetworkaccessmanager.h> |
15 | #include <QtNetwork/qhttpmultipart.h> |
16 | |
17 | #ifndef QT_NO_SSL |
18 | #include <QtNetwork/qsslconfiguration.h> |
19 | #endif |
20 | |
21 | QT_BEGIN_NAMESPACE |
22 | |
23 | using namespace Qt::StringLiterals; |
24 | |
25 | /*! |
26 | \class QAbstractOAuth2 |
27 | \inmodule QtNetworkAuth |
28 | \ingroup oauth |
29 | \brief The QAbstractOAuth2 class is the base of all |
30 | implementations of OAuth 2 authentication methods. |
31 | \since 5.8 |
32 | |
33 | The class defines the basic interface of the OAuth 2 |
34 | authentication classes. By inheriting this class, you |
35 | can create custom authentication methods using the OAuth 2 |
36 | standard for different web services. |
37 | |
38 | A description of how OAuth 2 works can be found in: |
39 | \l {https://tools.ietf.org/html/rfc6749}{The OAuth 2.0 |
40 | Authorization Framework} |
41 | */ |
42 | |
43 | /*! |
44 | \page oauth-http-method-alternatives |
45 | \title OAuth2 HTTP method alternatives |
46 | \brief This page provides alternatives for QtNetworkAuth |
47 | OAuth2 HTTP methods. |
48 | |
49 | QtNetworkAuth provides HTTP Methods such as \l {QAbstractOAuth::get()} |
50 | for issuing authenticated requests. In the case of OAuth2, |
51 | this typically means setting the |
52 | \l {QHttpHeaders::WellKnownHeader}{Authorization} header, as |
53 | specified in \l {https://datatracker.ietf.org/doc/html/rfc6750#section-2.1} |
54 | {RFC 6750}. |
55 | |
56 | Since this operation is straightforward to do, it is better to use |
57 | the normal QtNetwork HTTP method APIs directly, and set this header |
58 | manually. These QtNetwork APIs have less assumptions on the message |
59 | content types and provide a broader set of APIs. |
60 | |
61 | See \l QRestAccessManager, \l QNetworkAccessManager, QNetworkRequest, |
62 | QNetworkRequestFactory. |
63 | |
64 | \section1 QNetworkRequest |
65 | |
66 | The needed \e Authorization header can be set directly on each |
67 | request needing authorization. |
68 | |
69 | \code |
70 | using namespace Qt::StringLiterals; |
71 | |
72 | QOAuth2AuthorizationCodeFlow m_oauth; |
73 | QNetworkRequest request; |
74 | |
75 | QHttpHeaders headers; |
76 | headers.append(QHttpHeaders::WellKnownHeader::Authorization, u"Bearer "_s + m_oauth.token()); |
77 | request.setHeaders(headers); |
78 | \endcode |
79 | |
80 | After setting the header, use the request normally with either |
81 | \l QRestAccessManager or \l QNetworkAccessManager. |
82 | |
83 | \section1 QNetworkRequestFactory |
84 | |
85 | QNetworkRequestFactory is a convenience class introduced in Qt 6.7. |
86 | It provides a suitable method for this task: |
87 | \l {QNetworkRequestFactory::setBearerToken()}, as illustrated |
88 | by the code below. |
89 | |
90 | \code |
91 | QNetworkRequestFactory m_api({"https://www.example.com/v3"}); |
92 | QOAuth2AuthorizationCodeFlow m_oauth; |
93 | // ... |
94 | connect(&m_oauth, &QOAuth2AuthorizationCodeFlow::granted, this, [this]{ |
95 | m_api.setBearerToken(m_oauth.token().toLatin1()); |
96 | }); |
97 | \endcode |
98 | |
99 | After setting the bearer token, use the request factory normally |
100 | with either \l QRestAccessManager or \l QNetworkAccessManager. |
101 | */ |
102 | |
103 | /*! |
104 | \property QAbstractOAuth2::scope |
105 | \brief This property holds the desired scope which defines the |
106 | permissions requested by the client. |
107 | |
108 | The scope value is updated to the scope value granted by the |
109 | authorization server. In case of an empty scope response, the |
110 | \l {https://datatracker.ietf.org/doc/html/rfc6749#section-5.1} |
111 | {requested scope is assumed as granted and does not change}. |
112 | */ |
113 | |
114 | /*! |
115 | \property QAbstractOAuth2::userAgent |
116 | This property holds the User-Agent header used to create the |
117 | network requests. |
118 | |
119 | The default value is "QtOAuth/1.0 (+https://www.qt.io)". |
120 | */ |
121 | |
122 | /*! |
123 | \property QAbstractOAuth2::clientIdentifierSharedKey |
124 | This property holds the client shared key used as a password if |
125 | the server requires authentication to request the token. |
126 | */ |
127 | |
128 | /*! |
129 | \property QAbstractOAuth2::state |
130 | This property holds the string sent to the server during |
131 | authentication. The state is used to identify and validate the |
132 | request when the callback is received. |
133 | */ |
134 | |
135 | /*! |
136 | \property QAbstractOAuth2::expiration |
137 | This property holds the expiration time of the current access |
138 | token. An invalid value means that the authorization server hasn't |
139 | provided a valid expiration time. |
140 | |
141 | \sa QDateTime::isValid() |
142 | */ |
143 | |
144 | /*! |
145 | \fn QAbstractOAuth2::error(const QString &error, const QString &errorDescription, const QUrl &uri) |
146 | |
147 | Signal emitted when the server responds to the authorization request with |
148 | an error as defined in \l {https://www.rfc-editor.org/rfc/rfc6749#section-5.2} |
149 | {RFC 6749 error response}. |
150 | |
151 | \a error is the name of the error; \a errorDescription describes the error |
152 | and \a uri is an optional URI containing more information about the error. |
153 | |
154 | \sa QAbstractOAuth::requestFailed() |
155 | */ |
156 | |
157 | /*! |
158 | \fn QAbstractOAuth2::authorizationCallbackReceived(const QVariantMap &data) |
159 | |
160 | Signal emitted when the reply server receives the authorization |
161 | callback from the server: \a data contains the values received |
162 | from the server. |
163 | */ |
164 | |
165 | using OAuth2 = QAbstractOAuth2Private::OAuth2KeyString; |
166 | const QString OAuth2::accessToken = u"access_token"_s ; |
167 | const QString OAuth2::apiKey = u"api_key"_s ; |
168 | const QString OAuth2::clientIdentifier = u"client_id"_s ; |
169 | const QString OAuth2::clientSharedSecret = u"client_secret"_s ; |
170 | const QString OAuth2::code = u"code"_s ; |
171 | const QString OAuth2::error = u"error"_s ; |
172 | const QString OAuth2::errorDescription = u"error_description"_s ; |
173 | const QString OAuth2::errorUri = u"error_uri"_s ; |
174 | const QString OAuth2::expiresIn = u"expires_in"_s ; |
175 | const QString OAuth2::grantType = u"grant_type"_s ; |
176 | const QString OAuth2::redirectUri = u"redirect_uri"_s ; |
177 | const QString OAuth2::refreshToken = u"refresh_token"_s ; |
178 | const QString OAuth2::responseType = u"response_type"_s ; |
179 | const QString OAuth2::scope = u"scope"_s ; |
180 | const QString OAuth2::state = u"state"_s ; |
181 | const QString OAuth2::tokenType = u"token_type"_s ; |
182 | const QString OAuth2::codeVerifier = u"code_verifier"_s ; |
183 | const QString OAuth2::codeChallenge = u"code_challenge"_s ; |
184 | const QString OAuth2::codeChallengeMethod = u"code_challenge_method"_s ; |
185 | |
186 | QAbstractOAuth2Private::QAbstractOAuth2Private(const std::pair<QString, QString> &clientCredentials, |
187 | const QUrl &authorizationUrl, |
188 | QNetworkAccessManager *manager) : |
189 | QAbstractOAuthPrivate("qt.networkauth.oauth2" , |
190 | authorizationUrl, |
191 | clientCredentials.first, |
192 | manager), |
193 | clientIdentifierSharedKey(clientCredentials.second) |
194 | {} |
195 | |
196 | QAbstractOAuth2Private::~QAbstractOAuth2Private() |
197 | {} |
198 | |
199 | void QAbstractOAuth2Private::setExpiresAt(const QDateTime &expiration) |
200 | { |
201 | Q_ASSERT(!expiration.isValid() || expiration.timeSpec() == Qt::TimeSpec::UTC); |
202 | if (expiresAtUtc == expiration) |
203 | return; |
204 | Q_Q(QAbstractOAuth2); |
205 | expiresAtUtc = expiration; |
206 | emit q->expirationAtChanged(expiration: expiresAtUtc.toLocalTime()); |
207 | } |
208 | |
209 | QString QAbstractOAuth2Private::generateRandomState() |
210 | { |
211 | return QString::fromLatin1(ba: QAbstractOAuthPrivate::generateRandomBase64String(length: 8)); |
212 | } |
213 | |
214 | QNetworkRequest QAbstractOAuth2Private::createRequest(QUrl url, const QVariantMap *parameters) |
215 | { |
216 | QUrlQuery query(url.query()); |
217 | |
218 | QNetworkRequest request; |
219 | if (parameters) { |
220 | for (auto it = parameters->begin(), end = parameters->end(); it != end; ++it) |
221 | query.addQueryItem(key: it.key(), value: it.value().toString()); |
222 | url.setQuery(query); |
223 | } else { // POST, PUT request |
224 | addContentTypeHeaders(request: &request); |
225 | } |
226 | |
227 | request.setUrl(url); |
228 | request.setHeader(header: QNetworkRequest::UserAgentHeader, value: userAgent); |
229 | const QString bearer = bearerFormat.arg(a: token); |
230 | request.setRawHeader(headerName: "Authorization" , value: bearer.toUtf8()); |
231 | return request; |
232 | } |
233 | |
234 | /*! |
235 | \reimp |
236 | */ |
237 | void QAbstractOAuth2::prepareRequest(QNetworkRequest *request, const QByteArray &verb, |
238 | const QByteArray &body) |
239 | { |
240 | Q_D(QAbstractOAuth2); |
241 | Q_UNUSED(verb); |
242 | Q_UNUSED(body); |
243 | request->setHeader(header: QNetworkRequest::UserAgentHeader, value: d->userAgent); |
244 | const QString bearer = d->bearerFormat.arg(a: d->token); |
245 | request->setRawHeader(headerName: "Authorization" , value: bearer.toUtf8()); |
246 | } |
247 | |
248 | /*! |
249 | Constructs a QAbstractOAuth2 object using \a parent as parent. |
250 | */ |
251 | QAbstractOAuth2::QAbstractOAuth2(QObject *parent) : |
252 | QAbstractOAuth2(nullptr, parent) |
253 | {} |
254 | |
255 | /*! |
256 | Constructs a QAbstractOAuth2 object using \a parent as parent and |
257 | sets \a manager as the network access manager. |
258 | */ |
259 | QAbstractOAuth2::QAbstractOAuth2(QNetworkAccessManager *manager, QObject *parent) : |
260 | QAbstractOAuth(*new QAbstractOAuth2Private(std::make_pair(x: QString(), y: QString()), |
261 | QUrl(), |
262 | manager), |
263 | parent) |
264 | {} |
265 | |
266 | QAbstractOAuth2::QAbstractOAuth2(QAbstractOAuth2Private &dd, QObject *parent) : |
267 | QAbstractOAuth(dd, parent) |
268 | {} |
269 | |
270 | void QAbstractOAuth2::setResponseType(const QString &responseType) |
271 | { |
272 | Q_D(QAbstractOAuth2); |
273 | if (d->responseType != responseType) { |
274 | d->responseType = responseType; |
275 | Q_EMIT responseTypeChanged(responseType); |
276 | } |
277 | } |
278 | |
279 | /*! |
280 | Destroys the QAbstractOAuth2 instance. |
281 | */ |
282 | QAbstractOAuth2::~QAbstractOAuth2() |
283 | {} |
284 | |
285 | /*! |
286 | The returned URL is based on \a url, combining it with the given |
287 | \a parameters and the access token. |
288 | */ |
289 | QUrl QAbstractOAuth2::createAuthenticatedUrl(const QUrl &url, const QVariantMap ¶meters) |
290 | { |
291 | Q_D(const QAbstractOAuth2); |
292 | if (Q_UNLIKELY(d->token.isEmpty())) { |
293 | qCWarning(d->loggingCategory, "Empty access token" ); |
294 | return QUrl(); |
295 | } |
296 | QUrl ret = url; |
297 | QUrlQuery query(ret.query()); |
298 | query.addQueryItem(key: OAuth2::accessToken, value: d->token); |
299 | for (auto it = parameters.begin(), end = parameters.end(); it != end ;++it) |
300 | query.addQueryItem(key: it.key(), value: it.value().toString()); |
301 | ret.setQuery(query); |
302 | return ret; |
303 | } |
304 | |
305 | /*! |
306 | \deprecated [6.11] Please use QtNetwork classes directly instead, see |
307 | \l {OAuth2 HTTP method alternatives}{HTTP method alternatives}. |
308 | |
309 | Sends an authenticated HEAD request and returns a new |
310 | QNetworkReply. The \a url and \a parameters are used to create |
311 | the request. |
312 | |
313 | \b {See also}: \l {https://tools.ietf.org/html/rfc2616#section-9.4} |
314 | {Hypertext Transfer Protocol -- HTTP/1.1: HEAD} |
315 | */ |
316 | QNetworkReply *QAbstractOAuth2::(const QUrl &url, const QVariantMap ¶meters) |
317 | { |
318 | Q_D(QAbstractOAuth2); |
319 | QNetworkReply *reply = d->networkAccessManager()->head(request: d->createRequest(url, parameters: ¶meters)); |
320 | connect(sender: reply, signal: &QNetworkReply::finished, context: this, slot: [this, reply]() { emit finished(reply); }); |
321 | return reply; |
322 | } |
323 | |
324 | /*! |
325 | \deprecated [6.11] Please use QtNetwork classes directly instead, see |
326 | \l {OAuth2 HTTP method alternatives}{HTTP method alternatives}. |
327 | |
328 | Sends an authenticated GET request and returns a new |
329 | QNetworkReply. The \a url and \a parameters are used to create |
330 | the request. |
331 | |
332 | \b {See also}: \l {https://tools.ietf.org/html/rfc2616#section-9.3} |
333 | {Hypertext Transfer Protocol -- HTTP/1.1: GET} |
334 | */ |
335 | QNetworkReply *QAbstractOAuth2::get(const QUrl &url, const QVariantMap ¶meters) |
336 | { |
337 | Q_D(QAbstractOAuth2); |
338 | QNetworkReply *reply = d->networkAccessManager()->get(request: d->createRequest(url, parameters: ¶meters)); |
339 | connect(sender: reply, signal: &QNetworkReply::finished, context: this, slot: [this, reply]() { emit finished(reply); }); |
340 | return reply; |
341 | } |
342 | |
343 | /*! |
344 | \deprecated [6.11] Please use QtNetwork classes directly instead, see |
345 | \l {OAuth2 HTTP method alternatives}{HTTP method alternatives}. |
346 | |
347 | Sends an authenticated POST request and returns a new |
348 | QNetworkReply. The \a url and \a parameters are used to create |
349 | the request. |
350 | |
351 | \b {See also}: \l {https://tools.ietf.org/html/rfc2616#section-9.5} |
352 | {Hypertext Transfer Protocol -- HTTP/1.1: POST} |
353 | */ |
354 | QNetworkReply *QAbstractOAuth2::post(const QUrl &url, const QVariantMap ¶meters) |
355 | { |
356 | Q_D(QAbstractOAuth2); |
357 | const auto data = d->convertParameters(parameters); |
358 | QT_IGNORE_DEPRECATIONS(return post(url, data);) |
359 | } |
360 | |
361 | /*! |
362 | \deprecated [6.11] Please use QtNetwork classes directly instead, see |
363 | \l {OAuth2 HTTP method alternatives}{HTTP method alternatives}. |
364 | |
365 | \since 5.10 |
366 | |
367 | \overload |
368 | |
369 | Sends an authenticated POST request and returns a new |
370 | QNetworkReply. The \a url and \a data are used to create |
371 | the request. |
372 | |
373 | \sa post(), {https://tools.ietf.org/html/rfc2616#section-9.6} |
374 | {Hypertext Transfer Protocol -- HTTP/1.1: POST} |
375 | */ |
376 | QNetworkReply *QAbstractOAuth2::post(const QUrl &url, const QByteArray &data) |
377 | { |
378 | Q_D(QAbstractOAuth2); |
379 | QNetworkReply *reply = d->networkAccessManager()->post(request: d->createRequest(url), data); |
380 | connect(sender: reply, signal: &QNetworkReply::finished, context: this, slot: [this, reply]() { emit finished(reply); }); |
381 | return reply; |
382 | } |
383 | |
384 | /*! |
385 | \deprecated [6.11] Please use QtNetwork classes directly instead, see |
386 | \l {OAuth2 HTTP method alternatives}{HTTP method alternatives}. |
387 | |
388 | \since 5.10 |
389 | |
390 | \overload |
391 | |
392 | Sends an authenticated POST request and returns a new |
393 | QNetworkReply. The \a url and \a multiPart are used to create |
394 | the request. |
395 | |
396 | \sa post(), QHttpMultiPart, {https://tools.ietf.org/html/rfc2616#section-9.6} |
397 | {Hypertext Transfer Protocol -- HTTP/1.1: POST} |
398 | */ |
399 | QNetworkReply *QAbstractOAuth2::post(const QUrl &url, QHttpMultiPart *multiPart) |
400 | { |
401 | Q_D(QAbstractOAuth2); |
402 | QNetworkReply *reply = d->networkAccessManager()->post(request: d->createRequest(url), multiPart); |
403 | connect(sender: reply, signal: &QNetworkReply::finished, context: this, slot: [this, reply]() { emit finished(reply); }); |
404 | return reply; |
405 | } |
406 | |
407 | /*! |
408 | \deprecated [6.11] Please use QtNetwork classes directly instead, see |
409 | \l {OAuth2 HTTP method alternatives}{HTTP method alternatives}. |
410 | |
411 | Sends an authenticated PUT request and returns a new |
412 | QNetworkReply. The \a url and \a parameters are used to create |
413 | the request. |
414 | |
415 | \b {See also}: \l {https://tools.ietf.org/html/rfc2616#section-9.6} |
416 | {Hypertext Transfer Protocol -- HTTP/1.1: PUT} |
417 | */ |
418 | QNetworkReply *QAbstractOAuth2::put(const QUrl &url, const QVariantMap ¶meters) |
419 | { |
420 | Q_D(QAbstractOAuth2); |
421 | const auto data = d->convertParameters(parameters); |
422 | QT_IGNORE_DEPRECATIONS(return put(url, data);) |
423 | } |
424 | |
425 | /*! |
426 | \deprecated [6.11] Please use QtNetwork classes directly instead, see |
427 | \l {OAuth2 HTTP method alternatives}{HTTP method alternatives}. |
428 | |
429 | \since 5.10 |
430 | |
431 | \overload |
432 | |
433 | Sends an authenticated PUT request and returns a new |
434 | QNetworkReply. The \a url and \a data are used to create |
435 | the request. |
436 | |
437 | \sa put(), {https://tools.ietf.org/html/rfc2616#section-9.6} |
438 | {Hypertext Transfer Protocol -- HTTP/1.1: PUT} |
439 | */ |
440 | QNetworkReply *QAbstractOAuth2::put(const QUrl &url, const QByteArray &data) |
441 | { |
442 | Q_D(QAbstractOAuth2); |
443 | QNetworkReply *reply = d->networkAccessManager()->put(request: d->createRequest(url), data); |
444 | connect(sender: reply, signal: &QNetworkReply::finished, context: this, slot: std::bind(f: &QAbstractOAuth::finished, args: this, args&: reply)); |
445 | return reply; |
446 | } |
447 | |
448 | /*! |
449 | \deprecated [6.11] Please use QtNetwork classes directly instead, see |
450 | \l {OAuth2 HTTP method alternatives}{HTTP method alternatives}. |
451 | |
452 | \since 5.10 |
453 | |
454 | \overload |
455 | |
456 | Sends an authenticated PUT request and returns a new |
457 | QNetworkReply. The \a url and \a multiPart are used to create |
458 | the request. |
459 | |
460 | \sa put(), QHttpMultiPart, {https://tools.ietf.org/html/rfc2616#section-9.6} |
461 | {Hypertext Transfer Protocol -- HTTP/1.1: PUT} |
462 | */ |
463 | QNetworkReply *QAbstractOAuth2::put(const QUrl &url, QHttpMultiPart *multiPart) |
464 | { |
465 | Q_D(QAbstractOAuth2); |
466 | QNetworkReply *reply = d->networkAccessManager()->put(request: d->createRequest(url), multiPart); |
467 | connect(sender: reply, signal: &QNetworkReply::finished, context: this, slot: std::bind(f: &QAbstractOAuth::finished, args: this, args&: reply)); |
468 | return reply; |
469 | } |
470 | |
471 | /*! |
472 | \deprecated [6.11] Please use QtNetwork classes directly instead, see |
473 | \l {OAuth2 HTTP method alternatives}{HTTP method alternatives}. |
474 | |
475 | Sends an authenticated DELETE request and returns a new |
476 | QNetworkReply. The \a url and \a parameters are used to create |
477 | the request. |
478 | |
479 | \b {See also}: \l {https://tools.ietf.org/html/rfc2616#section-9.7} |
480 | {Hypertext Transfer Protocol -- HTTP/1.1: DELETE} |
481 | */ |
482 | QNetworkReply *QAbstractOAuth2::deleteResource(const QUrl &url, const QVariantMap ¶meters) |
483 | { |
484 | Q_D(QAbstractOAuth2); |
485 | QNetworkReply *reply = d->networkAccessManager()->deleteResource( |
486 | request: d->createRequest(url, parameters: ¶meters)); |
487 | connect(sender: reply, signal: &QNetworkReply::finished, context: this, slot: [this, reply]() { emit finished(reply); }); |
488 | return reply; |
489 | } |
490 | |
491 | QString QAbstractOAuth2::scope() const |
492 | { |
493 | Q_D(const QAbstractOAuth2); |
494 | return d->scope; |
495 | } |
496 | |
497 | void QAbstractOAuth2::setScope(const QString &scope) |
498 | { |
499 | Q_D(QAbstractOAuth2); |
500 | if (d->scope != scope) { |
501 | d->scope = scope; |
502 | Q_EMIT scopeChanged(scope); |
503 | } |
504 | } |
505 | |
506 | QString QAbstractOAuth2::userAgent() const |
507 | { |
508 | Q_D(const QAbstractOAuth2); |
509 | return d->userAgent; |
510 | } |
511 | |
512 | void QAbstractOAuth2::setUserAgent(const QString &userAgent) |
513 | { |
514 | Q_D(QAbstractOAuth2); |
515 | if (d->userAgent != userAgent) { |
516 | d->userAgent = userAgent; |
517 | Q_EMIT userAgentChanged(userAgent); |
518 | } |
519 | } |
520 | |
521 | /*! |
522 | Returns the \l {https://tools.ietf.org/html/rfc6749#section-3.1.1} |
523 | {response_type} used. |
524 | */ |
525 | QString QAbstractOAuth2::responseType() const |
526 | { |
527 | Q_D(const QAbstractOAuth2); |
528 | return d->responseType; |
529 | } |
530 | |
531 | QString QAbstractOAuth2::clientIdentifierSharedKey() const |
532 | { |
533 | Q_D(const QAbstractOAuth2); |
534 | return d->clientIdentifierSharedKey; |
535 | } |
536 | |
537 | void QAbstractOAuth2::setClientIdentifierSharedKey(const QString &clientIdentifierSharedKey) |
538 | { |
539 | Q_D(QAbstractOAuth2); |
540 | if (d->clientIdentifierSharedKey != clientIdentifierSharedKey) { |
541 | d->clientIdentifierSharedKey = clientIdentifierSharedKey; |
542 | Q_EMIT clientIdentifierSharedKeyChanged(clientIdentifierSharedKey); |
543 | } |
544 | } |
545 | |
546 | QString QAbstractOAuth2::state() const |
547 | { |
548 | Q_D(const QAbstractOAuth2); |
549 | return d->state; |
550 | } |
551 | |
552 | void QAbstractOAuth2::setState(const QString &state) |
553 | { |
554 | Q_D(QAbstractOAuth2); |
555 | if (state != d->state) { |
556 | d->state = state; |
557 | Q_EMIT stateChanged(state); |
558 | } |
559 | } |
560 | |
561 | QDateTime QAbstractOAuth2::expirationAt() const |
562 | { |
563 | Q_D(const QAbstractOAuth2); |
564 | return d->expiresAtUtc.toLocalTime(); |
565 | } |
566 | |
567 | /*! |
568 | \brief Gets the current refresh token. |
569 | |
570 | Refresh tokens usually have longer lifespans than access tokens, |
571 | so it makes sense to save them for later use. |
572 | |
573 | Returns the current refresh token or an empty string, if |
574 | there is no refresh token available. |
575 | */ |
576 | QString QAbstractOAuth2::refreshToken() const |
577 | { |
578 | Q_D(const QAbstractOAuth2); |
579 | return d->refreshToken; |
580 | } |
581 | |
582 | /*! |
583 | \brief Sets the new refresh token \a refreshToken to be used. |
584 | |
585 | A custom refresh token can be used to refresh the access token via this method and then |
586 | the access token can be refreshed via QOAuth2AuthorizationCodeFlow::refreshAccessToken(). |
587 | |
588 | */ |
589 | void QAbstractOAuth2::setRefreshToken(const QString &refreshToken) |
590 | { |
591 | Q_D(QAbstractOAuth2); |
592 | if (d->refreshToken != refreshToken) { |
593 | d->refreshToken = refreshToken; |
594 | Q_EMIT refreshTokenChanged(refreshToken); |
595 | } |
596 | } |
597 | |
598 | #ifndef QT_NO_SSL |
599 | /*! |
600 | \since 6.5 |
601 | |
602 | Returns the TLS configuration to be used when establishing a mutual TLS |
603 | connection between the client and the Authorization Server. |
604 | |
605 | \sa setSslConfiguration(), sslConfigurationChanged() |
606 | */ |
607 | QSslConfiguration QAbstractOAuth2::sslConfiguration() const |
608 | { |
609 | Q_D(const QAbstractOAuth2); |
610 | return d->sslConfiguration.value_or(u: QSslConfiguration()); |
611 | } |
612 | |
613 | /*! |
614 | \since 6.5 |
615 | |
616 | Sets the TLS \a configuration to be used when establishing |
617 | a mutual TLS connection between the client and the Authorization Server. |
618 | |
619 | \sa sslConfiguration(), sslConfigurationChanged() |
620 | */ |
621 | void QAbstractOAuth2::setSslConfiguration(const QSslConfiguration &configuration) |
622 | { |
623 | Q_D(QAbstractOAuth2); |
624 | const bool configChanged = !d->sslConfiguration || (*d->sslConfiguration != configuration); |
625 | if (configChanged) { |
626 | d->sslConfiguration = configuration; |
627 | Q_EMIT sslConfigurationChanged(configuration); |
628 | } |
629 | } |
630 | |
631 | /*! |
632 | \fn void QAbstractOAuth2::sslConfigurationChanged(const QSslConfiguration &configuration) |
633 | \since 6.5 |
634 | |
635 | The signal is emitted when the TLS configuration has changed. |
636 | The \a configuration parameter contains the new TLS configuration. |
637 | |
638 | \sa sslConfiguration(), setSslConfiguration() |
639 | */ |
640 | #endif // !QT_NO_SSL |
641 | |
642 | QT_END_NAMESPACE |
643 | |
644 | #include "moc_qabstractoauth2.cpp" |
645 | |