Qt OAuth2 Überblick

OAuth2

RFC 6749 OAuth 2.0 definiert ein Autorisierungs-Framework, das die Autorisierung von Ressourcen ermöglicht, ohne sensible Benutzerdaten wie Passwörter preiszugeben.

Das OAuth2-Framework definiert verschiedene Client-Typen (öffentlich und vertraulich) sowie Abläufe (implizit, Autorisierungscode und verschiedene andere). Für typische Qt-Anwendungen sollte der Client-Typ als öffentliche native Anwendung betrachtet werden. Öffentlich bedeutet, dass der Anwendung nicht zugetraut wird, dass sie Geheimnisse, wie z. B. Passwörter, in der ausgelieferten Binärdatei enthält.

RFC 8252 OAuth 2.0 for Native Apps definiert die Best Practices für solche Anwendungen weiter. Unter anderem wird darin der Authorization Code Flow als empfohlener Fluss definiert, und daher bietet QtNetworkAuth eine konkrete Implementierung dieses Flusses.

Seit Qt 6.9 bietet QtNetworkAuth auch Unterstützung für RFC 8628 OAuth 2.0 Device Authorization Grant. Dieser Gerätefluss ist für verbundene Geräte gedacht, die nur begrenzte Eingabemöglichkeiten haben oder bei denen die Verwendung eines User-Agents oder Browsers nicht praktikabel ist. Beispiele für solche Geräte sind Fernsehgeräte, Medienkonsolen, Maschinen-HMIs und IoT-Geräte.

In der folgenden Tabelle sind die wichtigsten Aspekte der beiden konkreten OAuth2-Abläufe aufgeführt, die vom Modul QtNetworkAuth unterstützt werden:

AspektFluss des AutorisierungscodesFluss der Geräteautorisierung
NetzwerkverbindungJaJa
Benutzer-InteraktionBrowser / User-Agent auf demselben GerätBrowser / User-Agent auf einem anderen Gerät
Redirect-Behandlung erforderlichJaNein
Eingabefähigkeit auf dem GerätUmfangreiche EingabemöglichkeitenEingeschränkte oder keine Eingabemöglichkeiten
ZielgruppenDesktop und mobile AnwendungenTVs, Konsolen, HMIs, IoT-Geräte

OAuth2 erfordert die Verwendung eines User-Agents, der typischerweise ein Browser ist. Weitere Informationen finden Sie unter Qt OAuth2 Browser Support.

Qt OAuth2-Klassen

QtNetworkAuth bietet sowohl konkrete als auch abstrakte OAuth2-Klassen. Die abstrakten Klassen sind für die Implementierung benutzerdefinierter Abläufe gedacht, während die konkreten Klassen eine konkrete Implementierung bieten.

QtNetworkAuth Qt OAuth2 hat zwei abstrakte Klassen für die Implementierung von OAuth2-Flows:

Ablauf des Autorisierungscodes

Der Autorisierungscodefluss ist der empfohlene OAuth2-Fluss für native Anwendungen wie Qt-Anwendungen.

Das folgende Code-Snippet zeigt ein Beispiel für die Einrichtung:

QOAuth2AuthorizationCodeFlow m_oauth;
QOAuthUriSchemeReplyHandler m_handler;

m_oauth.setAuthorizationUrl(QUrl(authorizationUrl));
m_oauth.setTokenUrl(QUrl(accessTokenUrl));
m_oauth.setClientIdentifier(clientIdentifier);
m_oauth.setRequestedScopeTokens({scope});

connect(&m_oauth, &QAbstractOAuth::authorizeWithBrowser, this, &QDesktopServices::openUrl);
connect(&m_oauth, &QAbstractOAuth::granted, this, [this]() {
    // Here we use QNetworkRequestFactory to store the access token
    m_api.setBearerToken(m_oauth.token().toLatin1());
    m_handler.close();
});

m_handler.setRedirectUrl(QUrl{"com.example.myqtapp://oauth2redirect"_L1});
m_oauth.setReplyHandler(&m_handler);

// Initiate the authorization
if (m_handler.listen()) {
    m_oauth.grant();
}

Stadien

Der Codefluss für die Autorisierung besteht aus zwei Hauptphasen: Ressourcenautorisierung (einschließlich der erforderlichen Benutzerauthentifizierung), gefolgt von der Anforderung eines Zugriffstokens. Darauf folgen optional die Verwendung des Zugangstokens und die Aktualisierung des Zugangstokens. Die folgende Abbildung veranschaulicht diese Phasen:

  • In der Autorisierungsphase wird der Benutzer authentifiziert, und der Benutzer autorisiert den Zugriff auf die Ressourcen. Dies erfordert eine Browser-Interaktion des Benutzers.
  • Nach der Autorisierung wird der erhaltene Autorisierungscode verwendet, um ein Zugriffstoken und optional ein Refresh-Token anzufordern.
  • Sobald das Zugriffstoken erworben wurde, verwendet die Anwendung es für den Zugriff auf die gewünschten Ressourcen. Das Zugriffstoken ist in den Ressourcenanforderungen enthalten, und es obliegt dem Ressourcenserver, die Gültigkeit des Tokens zu überprüfen. Es gibt mehrere Möglichkeiten, das Token als Teil der Anfragen einzubinden, aber die Aufnahme in den HTTP Authorization Header ist wohl die gebräuchlichste.
  • Auffrischung des Tokens. Zugriffstoken laufen in der Regel relativ schnell ab, beispielsweise in einer Stunde. Wenn die Anwendung zusätzlich zum Zugriffstoken ein Refresh-Token erhalten hat, kann das Refresh-Token zur Anforderung eines neuen Zugriffstokens verwendet werden. Refresh-Tokens sind langlebig und Anwendungen können sie aufbewahren, um eine neue Autorisierungsphase (und damit eine weitere Browser-Interaktion) zu vermeiden.

Details und Anpassungen

OAuth2-Abläufe sind dynamisch, und die Verfolgung der Details kann anfangs schwierig sein. Die folgende Abbildung veranschaulicht die wichtigsten Details eines erfolgreichen Autorisierungscodeflusses.

Aus Gründen der Übersichtlichkeit lässt die Abbildung einige weniger genutzte Signale weg, zeigt aber insgesamt die Details und die wichtigsten Anpassungspunkte. Bei den Anpassungspunkten handelt es sich um die verschiedenen Signale/Slots, die die Anwendung abfangen (und aufrufen) kann, sowie um die Rückrufe, die mit QAbstractOAuth::setModifyParametersFunction() und QAbstractOAuth2::setNetworkRequestModifier() eingestellt werden können.

Auswahl eines Reply-Handlers

Die Entscheidung, welcher Reply-Handler zu verwenden oder zu implementieren ist, hängt von der verwendeten redirect_uri ab. Die redirect_uri ist die Adresse, an die der Browser nach Abschluss der Autorisierungsphase weitergeleitet wird.

Im Zusammenhang mit nativen Anwendungen werden in RFC 8252 drei Haupttypen von URI-Schemata beschrieben: loopback, https, und private-use.

  • URIs zur privaten Nutzung: Können verwendet werden, wenn das Betriebssystem einer Anwendung erlaubt, ein benutzerdefiniertes URI-Schema zu registrieren. Beim Versuch, eine URL mit einem solchen benutzerdefinierten Schema zu öffnen, wird die entsprechende native Anwendung geöffnet. Siehe QOAuthUriSchemeReplyHandler.
  • HTTPS-URIs: Kann verwendet werden, wenn das Betriebssystem der Anwendung erlaubt, eine benutzerdefinierte HTTPS-URL zu registrieren. Beim Versuch, diese URL zu öffnen, wird die zugehörige native Anwendung geöffnet. Dieses Schema wird empfohlen, wenn das Betriebssystem es unterstützt. Siehe QOAuthUriSchemeReplyHandler.
  • Loopback-Schnittstellen: Diese werden üblicherweise für Desktop-Anwendungen und Anwendungen während der Entwicklung verwendet. QOAuthHttpServerReplyHandler ist so konzipiert, dass diese URIs von einem lokalen Server verarbeitet werden, der die Umleitung vornimmt.

Die Wahl hängt von verschiedenen Faktoren ab, wie z. B.:

  • Vom Anbieter des Autorisierungsservers unterstützte Umleitungs-URIs. Die Unterstützung variiert von Anbieter zu Anbieter und ist oft spezifisch für einen bestimmten Client-Typ und ein bestimmtes Betriebssystem. Außerdem kann die Unterstützung davon abhängen, ob die Anwendung veröffentlicht ist oder nicht.
  • URI-Umleitungsschemata, die von der/den Zielplattform(en) unterstützt werden.
  • Anwendungsspezifische Benutzerfreundlichkeit, Sicherheit und andere Anforderungen.

RFC 8252 empfiehlt die Verwendung des https Schemas aufgrund von Sicherheits- und Benutzerfreundlichkeitsvorteilen gegenüber den anderen Methoden.

Ablauf der Geräteautorisierung

Der Device Authorization Flow ist für angeschlossene Geräte gedacht, die nur begrenzte Eingabemöglichkeiten haben oder bei denen die Verwendung von Benutzer-Agenten/Browsern nicht sinnvoll ist.

Der folgende Codeschnipsel zeigt ein Beispiel für die Einrichtung:

m_deviceFlow.setAuthorizationUrl(QUrl(authorizationUrl)); m_deviceFlow.setTokenUrl(QUrl(accessTokenUrl)); m_deviceFlow.setRequestedScopeTokens({scope}); m_deviceFlow.setClientIdentifier(clientIdentifier);// Die Notwendigkeit für ein Client-Geheimnis hängt vom Autorisierungsserver abm_deviceFlow.setClientIdentifierSharedKey(clientSecret); connect(&m_deviceFlow, &QOAuth2DeviceAuthorizationFlow::authorizeWithUserCode, this,[](const QUrl &verificationUrl, const QString &userCode, const QUrl &completeVerificationUrl) { if (completeVerificationUrl.isValid()) { // Wenn der Autorisierungsserver eine vollständige URL //  zur Verfügung gestellt hat , die bereits die erforderlichen Daten als Teil der URL-Parameter enthält, // können Sie diese verwenden            qDebug() << "Complete verification uri:" << completeVerificationUrl;
        } else { // Der Autorisierungsserver hat nur die Verifizierungs-URL bereitgestellt; verwenden Sie diese            qDebug() << "Verification uri and usercode:" << verificationUrl << userCode;
        } } ); connect(&m_deviceFlow, &QAbstractOAuth::granted, this, [this](){ // Hier verwenden wir QNetworkRequestFactory, um das Zugriffstoken zu speichernm_api.setBearerToken(m_deviceFlow.token().toLatin1()); }); m_deviceFlow.grant();

Etappen

Der Geräteautorisierungsfluss hat drei Hauptphasen: Initialisierung der Autorisierung, Abfrage von Token und Abschluss der Autorisierung. Optional folgen die Verwendung der Token und die Aktualisierung der Token. Die folgende Abbildung veranschaulicht diese Phasen:

  • Die Autorisierung wird initialisiert, indem eine HTTP-Anfrage an den Autorisierungsserver gesendet wird. Der Autorisierungsserver liefert als Antwort einen Benutzercode, Verifizierungs-URL(s) und einen Gerätecode.
  • Nach der Initialisierung der Autorisierung erhält der Benutzer einen Benutzercode und eine oder mehrere Verifizierungs-URL(s), um die Autorisierung abzuschließen. Die Bereitstellung der Informationen für den Benutzer ist anwendungsfallspezifisch: Es kann sich um eine sichtbare URL auf dem Bildschirm, einen QR-Code, eine E-Mail usw. handeln.
  • Während der Benutzer auf den Abschluss der Autorisierung wartet, fragt der Gerätefluss den Autorisierungsserver nach Token ab. Der im vorherigen Schritt erhaltene Gerätecode wird verwendet, um die Autorisierungssitzung abzugleichen. Das Abfrageintervall wird vom Autorisierungsserver festgelegt und beträgt normalerweise 5 Sekunden.
  • Sobald der Benutzer die Autorisierung akzeptiert (oder verweigert) hat, antwortet der Autorisierungsserver auf eine Abfrage mit den angeforderten Token oder einem Fehlercode (im Falle einer Verweigerung), und die Autorisierung ist abgeschlossen.

Details und Anpassungen

Die folgende Abbildung veranschaulicht den Ablauf im Detail. Die Abbildung zeigt auch die wichtigsten Anpassungspunkte, die manchmal erforderlich sein können (z. B. proprietäre Parameter oder zusätzliche Authentifizierungsdaten).

Token aktualisieren

Ein vollständiger OAuth2-Ablauf erfordert eine Benutzerinteraktion, die sich störend auf das Benutzererlebnis auswirken kann. Um diese Interaktionen zu minimieren, können die Token aus der Sicht des Benutzers stillschweigend aufgefrischt werden.

Die Aktualisierung von Token erfordert, dass der Autorisierungsserver während der Autorisierung ein Refresh-Token bereitstellt. Die Bereitstellung eines Aktualisierungs-Tokens ist dem Autorisierungsserver überlassen: Einige Server stellen es immer bereit, andere nie, und wieder andere stellen es bereit, wenn eine bestimmte scope in der Autorisierungsanfrage vorhanden war.

Die folgende Abbildung veranschaulicht die Aktualisierung des Tokens im Detail:

Wie in der obigen Abbildung dargestellt, sind die üblichen Anpassungspunkte auch bei der Aktualisierung von Token verfügbar.

Um die Token nach einem Anwendungsstart zu aktualisieren, muss die Anwendung das Aktualisierungs-Token sicher aufbewahren und es mit QAbstractOAuth2::setRefreshToken() setzen. QAbstractOAuth2::refreshTokens() kann dann aufgerufen werden, um neue Token anzufordern.

Seit Qt 6.9 können Anwendungen auch die Aktualisierungsfunktion verwenden, um die Token automatisch zu aktualisieren - siehe QAbstractOAuth2::accessTokenAboutToExpire(), QAbstractOAuth2::autoRefresh und QAbstractOAuth2::refreshLeadTime.

Die Ablaufzeit für ein Refresh-Token wird im Allgemeinen nicht vom Autorisierungsserver angegeben (abgesehen von der Dokumentation des Servers). Ihre Gültigkeit kann von Tagen bis zu Monaten oder länger reichen. Außerdem können sie, wie andere Token auch, jederzeit vom Benutzer widerrufen und damit ungültig gemacht werden. Daher ist es wichtig, einen fehlgeschlagenen Aktualisierungsversuch mit QAbstractOAuth::requestFailed() oder QAbstractOAuth2::serverReportedErrorOccurred() richtig zu erkennen.

Qt OpenID Connect Unterstützung

OpenID Connect (OIDC) ist eine einfache Identitätsschicht, die auf dem OAuth2-Protokoll aufbaut. Während Autorisierung ein Mittel ist, um Benutzer zur Durchführung von Aktionen zu autorisieren, ermöglicht OIDC die Einrichtung einer vertrauenswürdigen Identität für einen Benutzer.

Die Unterstützung von Qt für OIDC beschränkt sich im Moment auf das Abrufen von ID-Tokens. Ein ID token ist ein JSON-Web-Token (JWT), das Angaben über das Authentifizierungsereignis enthält.

Insbesondere die Unterstützung für die Validierung von ID token oder die Entschlüsselung von ID token ist derzeit nicht implementiert.

Unter der Voraussetzung, dass die Anwendung in der Lage ist, die empfangenen Token zu validieren, kann das Token verwendet werden, um die Identität des Benutzers zuverlässig festzustellen (in dem Maße, wie der OIDC-Anbieter selbst vertrauenswürdig ist).

ID-Tokens sind sensible Informationen und sollten geheim gehalten werden. ID-Tokens sind nicht für das Versenden in API-Aufrufen vorgesehen - dafür ist das Zugriffstoken gedacht. Beachten Sie, dass einige Anbieter das gleiche JWT-Format für Zugriffstoken verwenden, was jedoch nicht mit den eigentlichen ID-Tokens zu verwechseln ist, die im Übrigen das gleiche Format verwenden. Bei ID-Tokens ist der Client, der das Token erhält, für die Verifizierung des Tokens verantwortlich, während bei Zugriffstokens der Ressourcenserver, der das Token akzeptiert, für die Verifizierung verantwortlich ist.

Abrufen eines ID-Tokens

Das Abrufen eines ID-Tokens ist dem Abrufen eines Zugriffstokens sehr ähnlich. Zunächst müssen wir den entsprechenden Bereich festlegen. Der Anbieter des Autorisierungsservers kann zusätzliche Bereichsangaben wie profile und email unterstützen, aber alle OIDC-Anfragen müssen den Bereich openid enthalten:

m_oauth.setRequestedScopeTokens({"openid"});

Für OIDC wird dringend empfohlen, den Parameter nonce zu verwenden. Dazu muss sichergestellt werden, dass der entsprechende NonceMode eingestellt ist.

// This is for illustrative purposes, 'Automatic' is the default mode
m_oauth.setNonceMode(QAbstractOAuth2::NonceMode::Automatic);

Als letzten Schritt können wir entweder auf das Signal QAbstractOAuth2::granted oder direkt auf QAbstractOAuth2::idTokenChanged warten:

connect(&m_oauth, &QAbstractOAuth2::idTokenChanged, this, [this](const QString &token) {
    Q_UNUSED(token); // Handle token
});

Validierung eines ID-Tokens

Die Validierung des empfangenen ID-Tokens ist ein entscheidender Teil des Ablaufs und, wenn vollständig implementiert, eine etwas komplizierte Aufgabe.

In ihren Grundzügen besteht die Validierung aus folgenden Schritten

  • Entschlüsseln des Tokens, falls erforderlich(siehe JWE)
  • Extrahieren des Token-Headers, der Nutzdaten und der Signatur
  • Validierung der Signatur
  • Validierung der Felder der Nutzdaten (z. B. aud, iss, exp, nonce, iat)

Qt bietet derzeit keine Unterstützung für die Validierung von ID-Token, aber es gibt mehrere C++-Bibliotheksoptionen, wie z. B. jwt-cpp.

Beispiel für die Überprüfung von ID-Tokens

Dieser Abschnitt veranschaulicht eine einfache Überprüfung mit Hilfe der jwt-cpp Bibliothek. Voraussetzung ist, dass die Entwicklungsumgebung über OpenSSL-Bibliotheken und den Include-Ordner jwt-cpp im Quellverzeichnis des Anwendungsprojekts verfügt.

In CMakeLists.txt des Anwendungsprojekts überprüfen wir zunächst, ob die Voraussetzungen erfüllt sind:

find_package(OpenSSL 1.0.0 QUIET)
set(JWT_CPP_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include")
if(OPENSSL_FOUND AND EXISTS "${JWT_CPP_INCLUDE_DIR}/jwt-cpp/jwt.h")

Dann fügen wir die erforderlichen Includes und Bibliotheken hinzu:

    target_include_directories(networkauth_oauth_snippets PRIVATE "${JWT_CPP_INCLUDE_DIR}")
    target_link_libraries(networkauth_oauth_snippets PRIVATE OpenSSL::SSL OpenSSL::Crypto)
    target_compile_definitions(networkauth_oauth_snippets PRIVATE JWT_CPP_AVAILABLE)

In die Quelldateien der Anwendung wird die Verifizierungsbibliothek aufgenommen:

#ifdef JWT_CPP_AVAILABLE
#include "jwt-cpp/jwt.h"
#endif

Sobald die Anwendung eine ID token erhält, ist es an der Zeit, sie zu verifizieren. Zuerst wird ein passender Schlüssel aus JSON Web Key Sets (JWKS, siehe OpenID Connect Discovery) gefunden.

try {
    const auto jwt = jwt::decode(m_oauth.idToken().toStdString());
    const auto jwks = jwt::parse_jwks(m_jwks->toJson(QJsonDocument::Compact).toStdString());
    const auto jwk = jwks.get_jwk(jwt.get_key_id());

Und dann erfolgt die eigentliche Verifizierung:

// Hier verwenden wir Modulus und Exponent zur Ableitung des Schlüsselsconst auto n = jwk.get_jwk_claim("n").as_string(); // Modulusconst auto e = jwk.get_jwk_claim("e").as_string(); // Exponentif (n.empty() || e.empty()) {    qWarning() << "Modulus or exponent empty";
   return false; }if (jwt.get_algorithm() != "RS256") { // Dieses Beispiel unterstützt nur RS256    qWarning() << "Unsupported algorithm:" << jwt.get_algorithm();
   return false; }if (jwk.get_jwk_claim("kty").as_string() != "RSA") {    qWarning() << "Unsupported key type:" << jwk.get_jwk_claim("kty").as_string();
   return false; }if (jwk.has_jwk_claim("use") && jwk.get_jwk_claim("use").as_string() != "sig") {    qWarning() << "Key not for signature" << jwk.get_jwk_claim("use").as_string();
   return false; }// Einfache minimale Verifizierung (lässt Sonderfälle und z.B. 'sub'-Verifizierung aus).// jwt-cpp prüft auch 'exp', 'iat' und 'nbf', wenn sie vorhanden sind.const auto keyPEM = jwt::helper::create_public_key_from_rsa_components(n, e);auto verifier = jwt::verify() .allow_algorithm(jwt::algorithm::rs256(keyPEM)) . with_claim("nonce", jwt::claim(m_oauth.nonce().toStdString())) . with_issuer(m_oidcConfig->value("issuer"_L1).toString().toStdString()) . with_audience(std::string(clientIdentifier.data())) . leeway(60UL); verifier.verify(jwt);qDebug() << "ID Token verified successfully";
return true; } catch(const std::exception &e) {// Fehler behandeln. Alternativ Fehlerparameter an jwt-cpp-Aufrufe übergebenqWarning() << "ID Token verification failed" << e.what();
return false; }

Es wird empfohlen, die aktuelle Dokumentation und Beispiele der verwendeten Bibliothek zu prüfen und sich mit der ID-Token-Verifizierung vertraut zu machen.

Lesen von ID-Token-Werten

Das ID-Token liegt im JSON-Web-Token (JWT) -Format vor und besteht aus einem Header-, Payload- und Signaturteil, die durch Punkte {'.'} getrennt sind.

Das Lesen der Werte des ID-Tokens ist sehr einfach. Nehmen wir als Beispiel eine struct:

struct IDToken {
    QJsonObject header;
    QJsonObject payload;
    QByteArray signature;
};

Und eine Funktion:

std::optional<IDToken> parseIDToken(const QString &token) const;

Das Token kann extrahiert werden:

if (token.isEmpty())
    return std::nullopt;

QList<QByteArray> parts = token.toLatin1().split('.');
if (parts.size() != 3)
    return std::nullopt;

QJsonParseError parsing;

QJsonDocument header = QJsonDocument::fromJson(
    QByteArray::fromBase64(parts.at(0), QByteArray::Base64UrlEncoding), &parsing);
if (parsing.error != QJsonParseError::NoError || !header.isObject())
    return std::nullopt;

QJsonDocument payload = QJsonDocument::fromJson(
    QByteArray::fromBase64(parts.at(1), QByteArray::Base64UrlEncoding), &parsing);
if (parsing.error != QJsonParseError::NoError || !payload.isObject())
    return std::nullopt;

QByteArray signature = QByteArray::fromBase64(parts.at(2), QByteArray::Base64UrlEncoding);

return IDToken{header.object(), payload.object(), signature};

In selteneren Fällen kann das Token mit JSON Web Encryption (JWE) verschlüsselt sein, das intern ein JWT-Token enthält. In diesem Fall muss das Token zuerst entschlüsselt werden.

OpenID Connect-Ermittlung

OpenID Connect Discovery definiert Mittel, um benötigte OpenID-Provider-Details zu entdecken, um mit ihnen zu interagieren. Dies beinhaltet Dinge wie authorization_endpoint und token_endpoint URLs.

Während diese Anbieterdetails statisch in der Anwendung konfiguriert werden können, kann das Ermitteln der Details zur Laufzeit mehr Flexibilität und Robustheit bei der Interaktion mit verschiedenen Anbietern bieten.

Der Abruf des Discovery-Dokuments ist eine einfache HTTP GET Anfrage. Das Dokument befindet sich normalerweise in https://<the-domain eg. example.com>/.well-known/openid_configuration

m_network->get(request, this, [this](QRestReply &reply) {
    if (reply.isSuccess()) {
        if (auto doc = reply.readJson(); doc && doc->isObject())
            m_oidcConfig = doc->object(); // Store the configuration
    }
});

Insbesondere für die Token-Validierung bietet das jwks_uri-Feld einen Link für den Zugriff auf die aktuellen (öffentlichen) Sicherheitsnachweise. Damit entfällt die Notwendigkeit, solche Anmeldeinformationen direkt in der Anwendung zu kodieren. Dies hilft auch bei der Schlüsselrotation; die Anbieter können die verwendeten Schlüssel von Zeit zu Zeit ändern, und daher ist es wichtig, einen aktuellen Schlüssel zu haben.

Das Abrufen der Schlüssel ist ebenfalls eine einfache HTTP GET Anfrage:

m_network->get(request, this, [this](QRestReply &reply) {
    if (reply.isSuccess()) {
        if (auto doc = reply.readJson(); doc && doc->isObject())
            m_jwks = doc; // Use the keys later to verify tokens
    }
});

Der Schlüsselsatz enthält in der Regel mehrere Schlüssel. Der richtige Schlüssel wird im JWT-Header angegeben (es muss darauf geachtet werden, dass die Schlüssel richtig zugeordnet werden; eine einfache Überprüfung des Feldes "key id" (kid) ist nicht ausreichend).

OpenID UserInfo Endpunkt

Eine alternative Möglichkeit, auf Benutzerinformationen zuzugreifen, ist die Verwendung des OpenID UserInfo Endpunkts, sofern der OIDC-Anbieter dies unterstützt. Die URL für die Benutzerinformationen befindet sich im Feld userinfo_endpoint des OpenID Connect Discovery-Dokuments.

Der UserInfo-Endpunkt verwendet nicht das ID-Token, sondern der Zugriff erfolgt über das Access-Token. Der Zugriff auf die Benutzerinformationen erfolgt ähnlich wie der Zugriff auf jede andere Ressource mit einem Zugriffstoken.

Angenommen, das Zugriffs-Token wird empfangen und z.B. gesetzt durch:

QNetworkRequestFactory userInfoApi(url);
userInfoApi.setBearerToken(m_oauth.token().toLatin1());

Dann ist der Zugriff auf die Benutzerdaten eine HTTP GET Anfrage:

m_network->get(userInfoApi.createRequest(), this, [this](QRestReply &reply) { if (reply.isSuccess()) { if(auto doc = reply.readJson(); doc &&  doc->isObject())            qDebug() << doc->object(); // Use the userinfo
    });

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.