Spécification du flux JWT Bearer
(traduction d’extrait de la spécification draft-ietf-oauth-jwt-bearer-07 section 1)
2.1. Utilisation de JWT en tant qu’accord d’autorisation (Authorization Grants)
Pour utiliser un jeton JWT pour la demande d’autorisation, émettez une requête de jeton d’accès telle que définie dans la section 4 de la spécification ’Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants [I-D.ietf-oauth-assertions]’ avec les valeurs de paramètres et encodages spécifiques suivants.
La valeur du paramètre "grant_type" DOIT être "urn : ietf : params : oauth : grant-type : jwt-bearer".
La valeur du paramètre "assertion" DOIT contenir un seul JWT.
Le paramètre "scope" peut être utilisé, tel que défini dans la spécification ’...’, pour indiquer la portée demandée.
L’authentification du client est facultative, comme décrit dans la Section 3.2.1 de OAuth 2.0 [RFC6749] et par conséquent, le "client_id" n’est nécessaire que lorsqu’un type d’authentification client qui repose sur ce paramètre est utilisé.
...
3.1. Traitement des accords d’autorisations
Les autorisations JWT peuvent être utilisées avec ou sans authentification ou identification du client. Que l’authentification du client soit requise ou non en conjonction avec un accord d’autorisation JWT, ainsi que les types d’authentification des clients pris en charge, sont des décisions de politique à la discrétion du serveur d’autorisation.
Cependant, si les informations d’identification du client sont présentes dans la demande, le serveur d’autorisation DOIT les valider.
Commentaire sur la sécurité du flux JWT Bearer
L’application cliente doit posséder un jeton JWT valide. Si elle l’a obtenu par OpenID Connect, elle ne peut l’avoir fait qu’en envoyant les identifiants d’application au point d’accès Token (dont le secret de l’application), et c’est précisément ce que le flux permet d’éviter. La solution : l’application cliente doit posséder la clé privée (ou y accéder) afin de générer le jeton JWT à son niveau. Cela nous place dans le cas très particulier des "applications de confiance". Nous savons que ce type d’applications doit se trouver dans un espace de communication protégé par TLS.
Ce flux peut être utilisé pour permettre à une application cliente d’accéder à une ressource protégée sans autorisation de l’utilisateur final (on considère que les données protégées sont la propriété de l’application). Dans cette configuration, nous sommes dans un flux comparable à l’Autorisation de Serveur à serveur (Client Credentials Grant), avec une sécurité supplémentaire : le jeton JWT signé apporte une certitude sur l’identité de l’application cliente.
Test du flux JWT Bearer avec OAuthSD
Quoiqu’il en soit, il est possible de mettre ce flux en oeuvre avec OAuthSD. Le script ci-dessous donne un exemple d’appel au point de terminaison Token avec un jeton JWT fabriqué localement.
PHP
- <?php
- /* test_JWTBearer.php
- Usage : https://oa.dnc.global/oidc/tests/test_JWTBearer.php
- Author :
- Bertrand Degoy https://degoy.com
- Credits :
- bschaffer https://github.com/bshaffer/oauth2-server-php
- Licence : MIT licence
- */
- // Autoloading by Composer
- require __DIR__ . '/../../vendor/autoload.php';
- OAuth2\Autoloader::register();
- //***** Configuration *****
- $client_id = 'testopenid'; // iss
- $user_id = 'bebert'; // subject
- $server = 'oa.dnc.global';
- $token_endpoint = 'https://' . $server . '/token';
- require_once __DIR__.'/../../oidc/includes/configure.php';
- require_once __DIR__.'/../../oidc/includes/utils.php';
- //*** End of configuration ***
- // Connect to database
- $cnx = new \PDO($connection['dsn'], $connection['username'], $connection['password']);
- // Get private key
- $stmt = $cnx->prepare($sql = "SELECT * FROM spip_public_keys WHERE client_id=:client_id");
- $keyinfo = $stmt->fetch(\PDO::FETCH_ASSOC);
- $response->setError(401, 'invalid_token', "Invalid aud"); //DEBUG only
- $response->send();
- die;
- }
- $private_key = $keyinfo['private_key'];
- $grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer';
- $jwt = generateJWT($private_key, $client_id, $user_id, 'https://' . $server);
- /**
- * Generate a JWT
- *
- * @param $privateKey The private key to use to sign the token
- * @param $iss The issuer, usually the client_id
- * @param $sub The subject, usually a user_id
- * @param $aud The audience, usually the URI for the oauth server
- * @param $exp The expiration date. If the current time is greater than the exp, the JWT is invalid
- * @param $nbf The "not before" time. If the current time is less than the nbf, the JWT is invalid
- * @param $jti The "jwt token identifier", or nonce for this JWT
- *
- * @return string
- */
- function generateJWT($privateKey, $iss, $sub, $aud, $exp = null, $nbf = null, $jti = null)
- {
- if (!$exp) {
- }
- 'iss' => $iss,
- 'sub' => $sub,
- 'aud' => $aud,
- 'exp' => $exp,
- );
- if ($nbf) {
- $params['nbf'] = $nbf;
- }
- if ($jti) {
- $params['jti'] = $jti;
- }
- $jwtUtil = new OAuth2\Encryption\Jwt();
- return $jwtUtil->encode($params, $privateKey, 'RS256');
- }
En cas de succès, le serveur retourne quelque chose comme :
{"access_token":"8d2bea8d956f74030d8837deacd6154dbc0df262","expires_in":3600,"token_type":"Bearer","scope":"basic"}