Accueil > OpenID Connect OAuth Server par DnC > Développer > OpenID Connect > API OpenID Connect : Points d’extrémité > OpenID Connect : UserInfo

Demande d’informations sur l’utilisateur (UserInfo Endpoint)

  publié le par DnC

Le point d’extrémité UserInfo du protocole OpenID Connect permet d’obtenir des informations sur l’utilisateur final authentifié.

Point d’extrémité UserInfo

L’URI est la suivante :

https://oa.dnc.global/userinfo

Forme de la demande UserInfo

La méthode de transmission recommandée pour la transmission du jeton d’accès à UserInfo est HTTP Auth Header :

 GET /userinfo HTTP/1.1
 Host: oa.dnc.global/userinfo
 Authorization: Bearer SlrqTTP7i88GkKGQWDbPs9RWVAnWHz5e7nxAV32hH

Exemples :

PHP

  1. // Méthode Auth Header
  2.  
  3.     $h = curl_init('https://oa.dnc.global/userinfo');
  4.     curl_setopt($h, CURLOPT_RETURNTRANSFER, true);
  5.     curl_setopt($h, CURLOPT_TIMEOUT, 10);
  6.     curl_setopt($h, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $access_token));
  7.  
  8.     $res = curl_exec($h);
  9.     if (!$res)
  10.         exit(curl_error($h));
  11.  
  12.     curl_close($h);
  13.     $res = json_decode($res, true);
  14.  
  15.     echo "UserInfo Response:\n";
  16.     print_r($res);

Télécharger

SPIP

  1. $url = "https://oa.dnc.global/userinfo";
  2. $options = array(
  3.     'methode' => 'GET',
  4.     'datas' => 'Authorization: Bearer ' . $access_token,
  5. );
  6. $resource_response = recuperer_url($url, $options);

Télécharger

Exemple de requête avec la méthode POST. Notez que le jeton d’accès est fourni sans l’indication ’Bearer’ :
PHP

  1. // Méthode Post
  2.  
  3.     $data2 = array(
  4.         'access_token' => $access_token,
  5.     );
  6.     $h = curl_init($userinfo_endpoint);
  7.     curl_setopt($h, CURLOPT_RETURNTRANSFER, true);
  8.     curl_setopt($h, CURLOPT_TIMEOUT, 10);
  9.     curl_setopt($h, CURLOPT_POST, true);
  10.     curl_setopt($h, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));     // semble facultatif : curl le fait pour nous?
  11.     curl_setopt($h, CURLOPT_POSTFIELDS, http_build_query($data2));
  12.     //*/

Télécharger

Réponse du serveur

En cas de succès, le serveur retourne une réponse HTTP 200.

Le corps de la réponse contient un tableau portant les informations suivantes :

index type valeur
status entier code HTTP
headers string Headers de la réponse
page string JSON Array :
La réponse est détaillée ici : Réponse UserInfo.

Note :
- La valeur (string) "null" est forcée pour tous les champs vides ou NULL.
- La spécification indique qu’il n’est pas garanti que la réponse UserInfo corresponde à l’utilisateur identifié par l’élément user_id du ID Token ID. Avant de considérer la réponse UserInfo comme valide, il convient de vérifier que la revendication user_id dans la réponse UserInfo Endpoint correspond exactement à la revendication user_id dans le Token ID.
- Par ailleurs, la spécification impose de vérifier un ID Token dès sa réception. Ceci veut dire que toute requête Userinfo devrait suivre le cycle : demande d’autorisation, validation du jeton ID Token, demande Userinfo, vérification de la concordance des user_id. C’est ce qui est décrit dans les exemples.
- Si la constante de configuration CHECK_CLIENT_IP est réglée à ’true’ (ce qui est fortement conseillé), et que la valeur de l’IP a été fournie lors de l’enregistrement de l’application cliente (ce qui est également conseillé), le contrôleur UserInfo vérifiera que l’IP de l’origine de la requête est conforme. Cela interdit à une application étrangère d’utiliser un jeton d’accès volé.

 

En cas d’échec, le corps de la réponse contient :

index type valeur
page string JSON Array :
error : (string) titre de l’erreur,
error_description : (string) description de l’erreur

La réponse HTTP ainsi que les valeurs de error et error_description sont données par le tableau suivant :

Réponse error titre de l’erreur error_description description de l’erreur Explication
400 invalid_request Only one method may be used to authenticate at a time (Auth header, GET or POST) N’utiliser qu’une seule méthode d’authentification à la fois.
400 invalid_request Malformed auth header La requête de type Auth header est mal formée
400 invalid_request When putting the token in the body, the method must be POST or PUT Si on place le token dans le corps de la requête, la méthode ne peut être que POST ou PUT
400 invalid_request The content type for POST requests must be "application/x-www-form-urlencoded l’IETF spécifie ce type de contenu. NB : tous les serveurs Web ne remplissent pas cette variable _SERVER voir http://tools.ietf.org/html/rfc6750#section-2.2
401 (vide) (vide) La requête ne comporte aucune authentification
401 invalid_token The access token provided is invalid Le jeton ne figure pas dans le tokenStorage du serveur. Très probablement une tentative de violation d’accès.
401 expired_token The access token provided has expired Le jeton a expiré. L’application doit obtenir un nouveau jeton et relancer la requête
401 malformed_token Malformed token (missing "expires"
401 malformed_token Malformed token (missing "client_id")
403 insufficient_scope The request requires higher privileges than provided by the access token L’application cliente n’a pas été inscrite avec le scope openid

Réponse UserInfo

  publié le par DnC

Le protocole OpenID Connect définit des informations de profil standard devant être retournées en réponse à une requête UserInfo.
Il permet également d’étendre ces données pour répondre aux besoins d’applications clientes spécifiques. OAuth Server by DnC propose un jeu étendu.
Cependant, il convient de définir avec soin les informations qui relèvent d’un serveur d’authentification et celles qui devraient être servies à part.

Informations de profil standard et scopes standards

La spécification de UserInfo dans le standard OpenID Connect figure ici : UserInfo Response

Dans l’état actuel du développement, OAuth Server by DnC fournit les déclarations (claims), autrement dit informations de profil, suivantes en fonction du scope (ou des scopes) :

Scope Informations de profil (claims)
profile name, family_name, given_name, middle_name, nickname, profile, picture, website, gender, birthday, zoneinfo, locale, updated_at
email email, verified
address address, street_address, locality, region, postal_code, country
phone phone_number

[dnc2]

Notes :
- La spécification indique qu’il n’est pas garanti que la réponse UserInfo Endpoint corresponde à l’utilisateur identifié par l’élément user_id du Token ID [1]. Avant de considérer la réponse UserInfo comme valide, il convient de vérifier que la déclaration sub dans la réponse UserInfo correspond exactement à la déclaration user_id dans le Token ID.
- La déclaration sub est toujours incluse dans la réponse, par défaut, c’est à dire y compris en l’absence de Scope.
- Lors de la certification OpenID Connect, nous avons constaté que la déclaration name est également exigée par défaut [2].
- La déclaration name est une valeur composée avec les valeurs d’autres champs en fonction de règles locales [3]. De ce fait (mais aussi en application des règles de normalisation des bases de données relationnelles), ce champ n’est pas présent dans la table users, mais il est calculé par le contrôleur UserInfo. Dans l’état actuel du développement, la valeur de name est déterminée comme suit :

  1. $name = strtoupper($userinfo['given_name']) . ' ' . strtoupper($userinfo['family_name']);

Informations de profil étendu

La définition standard des couples scope-claims n’est pas satisfaisante pour deux raisons principales :
- le scope profile appelle trop d’informations, mélangeant des information essentielles et légitimement acceptables par l’utilisateur final avec des informations secondaires et plus intimes, telles que gender et birthdate.
- à l’inverse, plus d’informations sur l’utilisateur devraient être disponibles.

La norme permettant de définir des scope et des claims additionnels, une implémentation spécifique d’OAuth Server by DnC pourrait exposer de nouveaux couples scope-claims mieux appropriés.

Voici par exemple des scopes permettant de définir des employés d’une entreprise :

Scope Informations de profil (claims)
job job_title, job_street_address, job_locality, job_region, job_postal_code, job_country, job_phone, job_phone2, job_mobile, job_fax, job_email, job_website
firm firm_name, firm_street_address, firm_locality, firm_region, firm_postal_code, firm_country, firm_phone, firm_phone2, firm_mobile, firm_fax, firm_email, firm_website
trading legalidentity, siret, rcs, vat_id, terms, rights

Voici un autre exemple permettant à une application eCommerce d’authentifier ses clients :

Scope Informations de profil (claims)
delivery delivery_fullname, delivery_street_address, delivery_locality, delivery_region, delivery_postal_code, delivery_country, delivery_phone, delivery_infos
billing billing_fullname, billing_street_address, billing_locality, billing_region, billing_postal_code, billing_country, billing_phone, billing_vat_id
bank bank_name, bank_full_address, bank_bic, bank_iban


Comment étendre les informations de profil ?

Il faut distinguer deux configurations du serveur d’authentification :

- le serveur est conçu pour des applications variées et non connues à l’avance (ce peut être un SaaS ouvert à la configuration d’applications par des administrateurs publics), et dans ce cas il parait souhaitable de le conserver conforme au standard OIDC. L’extension des informations de profil devrait alors se faire à l’aide de Web services distincts, propres aux applications.

- le serveur est un serveur privé mis en œuvre dans le cadre d’un domaine d’entreprise pour des applications connues (c’est le cas des serveurs d’authentification de G..., F..., Wordpress avec le jeton blog etc.). Dans ce cas, la meilleure solution pour la sécurité (et notamment pour appliquer le RGPD) consiste à compléter la table users de la base de données et à définir des scopes particuliers avec la liste d’informations qui leur est rattachée.

Dans le deuxième cas, une bonne pratique serait de conserver la réponse UserInfo conforme au standard lorsque l’on interroge le point d’extrémité UserInfo, et de créer un point d’extrémité spécifique, par exemple UserInfoExt pour les informations de profil étendues, ainsi qu’une table particulière dans la base de données. Cette pratique permettra de conserver le serveur conforme au standard et de mieux gérer le code ainsi que les données.

Il existe des informations complémentaires, connectez vous pour les voir.

Notes

[1Pourquoi ?

[2A étudier : est-ce conforme à la spécification ?

[3Voir la spécification § 2.4.2 : "End-User’s full name in displayable form including all name parts, ordered according to End-User’s locale and preferences."