Protocole

Demande d’authentification

Une application non authentifiée doit procéder à une demande d’authentification auprès du fournisseur d’identité Moovapps SSO.

Pour ce faire, il faut appliquer le scénario d’authentification appelé “Authorization code flow” Authorization code flow.

L’objectif est d’obtenir un code d’autorisation une fois l’authentification réalisée par le fournisseur d’identité Moovapps SSO.

Ce code d’autorisation, une fois consommé par l’application, permet d’obtenir un jeton d’api (protocole OAuth2) et un jeton d’identification (protocole OpenID Connect).

Obtention d’un code temporaire

Puisqu’il s’agit d’un protocole web, il requiert l’utilisation d’un navigateur web pour effectuer une simple redirection vers le serveur d’identité Moovapps SSO.

Eemple :

https:// ___ /**tenant**/auth/oauth2/authorize

Cette demande d’authentification auprès du fournisseur d’identité Moovapps SSO doit inclure :

  • L’identifiant de l’application qui fait la demande, appelé “client_Id” : client_id=XXXX
  • Le type de réponse que l’on veut obtenir une fois l’authentification effectuée par le serveur d’identité Moovapps SSO, à savoir le code : response_type=code
  • L’url de retour de l’application, qui sera appelée une fois l’authentification effectuée par le fournisseur d’identitité Moovapps SSO, pour fournir le code appelée “redirect_uri”
  • Afin d’indiquer le protocole OpenId connect à utiliser en lieu et place du protocole Oauth2 par défaut, il faut préfixer le scope par openid: scope=openid

authorization-code

Une fois l’authentification réalisée par le fournisseur d’identité Moovapps SSO, ce dernier utilise une simple redirection pour renvoyer un code d’autorisation au client d’origine.

Obtention des jetons définitifs

Le code d’autorisation ainsi obtenu, à usage unique et limité dans le temps, peut alors être utilisé uniquement par le client qui en a fait la demande. Il utilise pour cela l’api suivante, à laquelle il fournit son identifiant d’application (client_id) et son mot de passe (secret):

https:// ___ /tenant/auth/oauth2/token

Cette api REST de type POST, qui permet donc l’échange d’un code pour des jetons d’api et d’identification, requiert les paramètres dans le corps de la requète au format application/x-www-form-urlencoded suivant:

  • Le type de demande (grant type) pour indiquer que l’on échange un code temporaire pour des tokens : grant_type=authorization_code
  • Le code à consommer : code=xxxxx
  • L’url de redirection qui a servi à obtenir le code temporaire : redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb

Quant aux identifiants de sécurité (cient_id et client_secret), ils doivent être également encodés au format application/x-www-form-urlencoded, puis transmis au format basic authentication.

Exemple :

 POST /tenant/auth/oauth2/token HTTP/1.1
     
     Authorization: Basic eHh4eHg6MSUyNjIlMjYzJTI2NA==
     Content-Type: application/x-www-form-urlencoded
      
     grant_type=authorization_code&code=YYYYYY
     &redirect_uri=https%3A%2F%2FXXXX%2FXXX

Remarque: Le mot de passe devant rester confidentiel, il est recommandé de ne pas effectuer cet appel d’api coté client.

La réponse au format json de cette API comprend les éléments suivants:

  • Le token d’api appelé “access token”
  • Le type de token d’api “token_type”, dans notre cas “bearer”
  • La durée de validité du token en secondes “expires_in”
  • Le token longue durée “refresh_token” qui permet de regénérer un “access token”
  • Le token d’identification “id_token” OpenID Connect au format JWT

Exemple :

 HTTP/1.1 200 OK
   Content-Type: application/json
   Cache-Control: no-store
   Pragma: no-cache
 
   {
    "access_token": "SlAV32hkKG",
    "token_type": "Bearer",
    "refresh_token": "8xLOxBtZp8",
    "expires_in": 3600,
    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
      yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
      NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
      fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
      AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
      Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
      NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
      QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
      K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
      XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
   }

Renouvellement des jetons

Utillisation du jeton de renouvellement

Il est possible de renouveler les jetons à l’aide du jeton refresh_token prévu à cet effet. Pour cela il faut utiliser la même API REST que pour consommer le code d’autorisation mais avec les paramètres suivants:

  • le type de demande (grant type) pour indiquer que l’on utilise le refresh_token: grant_type=refresh_token
  • le refresh_token à consommer : refresh_token=xxxxx

Quant aux identifiants de sécurité (cient_id et client_secret), ils doivent être également encodés au format application/x-www-form-urlencoded, puis transmis au format basic authentication.

Exemple :

 POST /tenant/auth/oauth2/token HTTP/1.1
     
     Authorization: Basic eHh4eHg6MSUyNjIlMjYzJTI2NA==
     Content-Type: application/x-www-form-urlencoded
      
     grant_type=refresh_token&refresh_token=YYYYYY      

Demande de SSO silentieuse

En l’absence de jeton de rafraîchissement, il est possible d’effectuer une demande d’autorisation dite silencieuse (en désactivant toute interaction avec l’utilisateur) pour obtenir un nouveau code d’autorisation à l’aide du paramètre prompt à none.

Si la session sso est toujours valide, un nouveau code temporaire est retourné.

Si au contraire, le sso n’est pas valide, une erreur est renvoyée en lieu et place du code. Cette erreur permet d’en déterminer la raison (authentification requise, … )).

Gestion des érreurs

Echec de la demande d’autorisation

Si un code d’autorisation ne peut être retourné par le fournisseur d’identité Moovapps SSO au client qui en a fait la demande, une erreur et sa description sont retournées en lieu et place du paramètre de l’url de redirection du client

Exemple:

    error=login_required&error_description=The%20Authorization%20Server%20requires%20End-User%20authentication.

Echec de l’API

Si l’utilisation d’un code d’autorisation ou d’un refresh_token échoue via l’API REST, un flux json d’erreur est retourné au format suivant:

Exemple:


         HTTP/1.1 400 Bad Request
         Content-Type: application/json;charset=UTF-8
         Cache-Control: no-store

         Pragma: no-cache
         {
           "error":"invalid_request",
           "error_description"="The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed."
         }

Sécurisation du protocole

Il existe quelques pratiques à appliquer afin de sécuriser la transaction et éviter au client d’être abusé.

Parmi ces pratiques, deux sont primordiales!

Sécuriser le client

Afin de prévenir le client (seul détenteur du secret oauth2) d’une utilisation abusive de son url de validation du code d’authentification (redirect_uri), le client peut transmettre un paramètre supplémentaire (state) dans la demande d’autorisation.

Une fois l’authentification opérée par le fournisseur d’identité, le paramètre (state) en question est systématiquement retourné (redirect_uri) par ce dernier avec le code d’authentification (ou le code d’érreur).

Ce paramètre est donc pris en charge par le client et permet donc de valider la légitimité de la demande de validation du code, à savoir que c’est bien lui qui a émis la demande et personne d’autre.

Remarques:

  • Ce paramètre doit être opaque ou signé et son contenu doit être unique à chaque demande
  • Il est de préférence couplé au navigateur (cookie, ect..)
  • Ce paramètre peut également servir à conserver la raison initiale de la demande (acces à une resource précise, etc..) et donc de pouvoir rediriger vers le lien initial avant redirection vers le SSO Moovapps

Sécuriser le code d’autorisation

Le client étant en possession du secret, il est le seul en mesure de consommer le code. Cependant le client est considéré comme public lorsque le secret ne peut être offusqué (retro engineering de l’application native).

Afin de prévenir la consommation d’un code par un tiers parce que le secret n’est pas offuscable, l’utilisation du code PKCE est alors obligatoire.

Il s’agit de fournir les paramètres supplémentaires suivants en query lors de la demande d’autorisation:

  • code_challenge: un SHA-256 base64 urlencodé d’une valeur aplhanumérique aléatoire
  • code_challenge_method: S256
    exemple:
code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256

Le code d’authorisation renvoyé au client (redirect_uri) par le fournisseur d’identitité Moovapps pourra donc être utilisé uniquement si lors de la consommation de ce code, la valeur alphanumérique transmise à ce moment (paramètre code_verifier), correspond en tout point.

En effet, le code_verifier est converti par le fournisseur d’identité avec le même algorithme que celui appliqué par le client Openid/OAuth2 lors de la demande d’autorisation. Le but est de comparer si le code est bien associé à cette valeur. Cela garantit la transaction en la rendant unique, et le client est seul en possession du code qu’il a généré au moment de la demande.

Remarque:

  • La valeur du code est une chaine alphanumérique [A-Z] / [a-z] / [0-9] / “-” / “.” / “_” / “~” d’une longueur de 43 à 128 de long
  • La valeur doit être aléatoire et unique
  • Cette méthode doit de préférence être appliquée dans tous les cas et pas seulement pour une application native