API Progression
Point d’entrée
Méthode | URL | Description | Paramètres | Réponse |
---|---|---|---|---|
GET | / |
Configuration du serveur | Config |
Liens :
Nom | Description |
---|---|
inscription | Inscription d’un utilisateur |
Authentification
Trois méthodes permettent l’authentification pour n’importe quelle requête :
Identifiant et mot de passe
Dans l’entête
Authorization
, méthodeBasic
, les paramètres suivants séparés par des deux-points (:) et encodés en base64Paramètre Description Type Défaut identifiant Nom d’utilisateur ou courriel str password Mot de passe str domaine Domaine LDAP str « » Exemple :
Authorization: Basic Ym9iOnBhc3N3b3JkOmV4ZW1wbGUuY29t
Identifiant et clé d’accès
Dans l’entête
Authorization
, méthodeKey
, les paramètres suivants séparés par des deux-points (:) et encodés en base64Paramètre Description Type Défaut identifiant Nom d’utilisateur ou courriel str key_name Identifiant de la clé Clé key_secret Secret correspondant à la clé str La clé nommée par
key_name
doit exister avec la portée «auth». Le secret peut alternativement être passé via cookie sécurisé.Token JWT
Dans l’entête
Authorization
, un Token d’identification «au porteur» :Authorization: Bearer <token JWT>
L’authentification par token ne permet pas de générer un token d’identification ni une clé d’authentification.
Autorisation
L’autorisation d’accéder aux ressources est donnée par un Token dans l’entête Authorization
ou dans le paramètre tkres
:
Paramètre | Description | Type | Défaut |
---|---|---|---|
identifiant | Nom d’utilisateur ou courriel | str | |
tkres | Token d’accès | Token |
Ressources
Les ressources échangées sont représentées en format JSON-API
Avancement
L’avancement d’un utilisateur pour une question.
Identifiant :
username/question_uri
Propriétés :
Nom | Type | Valeurs | Description |
---|---|---|---|
état | str | « début » | Aucune tentative envoyée |
« non_réussi » | Au moins une tentative, mais aucune n’est réussie | ||
« réussi » | Au moins une tentative dont une réussie | ||
titre | str | Le titre de la question tel qu’il était lors de la dernière tentative | |
niveau | str | Le niveau de la question tel qu’il était lors de la dernière tentative | |
date_modification | int | La date de la dernière tentative | |
date_réussie | int | La date de la première tentative réussie | |
extra | str | Infos extra à stoquer avec l’Avancement |
Relations :
Nom | Cardinalité | Type | Description |
---|---|---|---|
tentatives | 1-n | Tentatives | liste de Tentatives effectuées |
Liens :
Nom | Description |
---|---|
tentative | Soumettre une nouvelle tentative |
Clé
Une clé donnant accès à un sous-ensemble des services ou ressources de l’API. Les clés peuvent être octroyées temporairement ou être révoquées. Une clé peut être utilisée en lieu et place d’un mot de passe au moment d’effectuer une authentification. Le token JWT retourné après une authentification réussie peut être utilisé pour accéder aux services et ressources donnés par la portée de la clé.
Identifiant :
username/nom
Propriétés :
Nom | Type | Valeurs | Description |
---|---|---|---|
secret | str | valeur secrète de la clé | |
création | int | Timestamp de création | |
expiration | int | Timestamp d’expiration, 0=n’expire jamais | |
portée | str | Service ou ressource accessible par la clé. | |
« révoquée » | La clé est révoquée pour tout service ou ressource | ||
« authentification » | La clé peut être utilisée pour authentifier l’utilisateur |
Config
Configuration du serveur
Nom | Type | Valeurs | Description |
---|---|---|---|
config | dict | Dictionnaire de configurations | |
version | str | Version actuelle du serveur |
Commentaire
Un message sur une tentative écrit par un utilisateur.
Identifiant :
username/question_uri/date_soumission/numéro
Propriétés:
Nom | Type | Valeurs | Description | Défaut |
---|---|---|---|---|
message | str | |||
créateur | str | nom d’utilisateur du créateur | Utilisateur authentifié | |
date | int | timestamp de création | Date courante | |
numéro_ligne | int | numéro de ligne où s’applique le commentaire |
Ébauche
Une ébauche de solution fournie comme point de départ à la résolution de l’exercice.
Identifiant :
question_uri/langage
Propriétés:
Nom | Type | Valeurs | Description |
---|---|---|---|
langage | str | Langage de programmation de l’ébauche | |
code | str | Code de l’ébauche |
Question
Une question générique.
Identifiant :
URI
Hiérarchie
Question ▲ ├ QuestionProg ├ QuestionSys └ QuestionBD
Propriétés :
Nom | Type | Valeurs | Description |
---|---|---|---|
niveau | str | ||
titre | str | ||
description | str | ||
objectif | str | ||
énoncé | str ou liste de dict | ||
auteur | str | ||
licence | str | ||
sous_type | str | questionProg | |
questionSys | |||
questionBD |
Question (sous-type QuestionProg)
Une question spécifiquement de programmation.
Relations :
Nom | Cardinalité | Type | Description |
---|---|---|---|
ebauches | 1-n | Ébauche | liste d’ébauches de Solution |
tests | 1-n | Test | liste de Tests de validation |
Question (sous-type QuestionSys)
Une question spécifiquement de type système
Relations :
Nom | Cardinalité | Type | Description |
---|---|---|---|
image | 1 | str | image du conteneur |
utilisateur | 1 | str | utilisateur du conteneur |
solution | 1 | str | solution du test, s’il y a lieu |
tests | 1-n | Test | liste de Tests de validation |
Résultat
Le résultat d’un test pour une solution proposée.
Identifiant :
username/question_uri/hash
Propriétés:
Nom | Type | Valeurs | Description |
---|---|---|---|
sortie_observée | str | Sortie standard du Test | |
sortie_erreur | str | Sortie d’erreur du Test | |
résultat | bool | Vrai si le Test a été validé avec un code de retour de 0 et une sortie observée égale à la sortie attendue | |
feedback | str | Rétroaction pour ce résultat de test | |
temps_exécution | int | temps d’exécution en ms |
Sauvegarde automatique
La sauvegarde automatique du travail d’un utilisateur pour une question et dans un langage spécifique.
Identifiant :
username/question_uri/langage
Propriétés:
Nom | Type | Valeurs |
---|---|---|
date_sauvegarde | int | timestamp |
code | str |
Tentative
Une tentative de réponse à une question.
Identifiant :
username/question_uri/date_soumission
Hiérarchie
Tentative ▲ ├ TentativeProg ├ TentativeSys ├ TentativeBD
Propriétés :
Nom | Type | Valeurs | Description |
---|---|---|---|
date_soumission | int | timestamp | |
feedback | str | ||
réussi | bool | vrai ssi la tentative a correctement répondu à la question | |
temps_exécution | int | temps d’exécution en ms | |
sous-type | str | tentativeProg | Sous-type de la ressource |
tentativeSys | |||
tentativeBD |
Relations :
Nom | Cardinalité | Type | Description |
---|---|---|---|
résultats | 1-n | Résultat | les résultats de test |
Tentative (sous-type tentativeProg)
Une tentative de réponse à une QuestionProg.
Propriétés:
Nom | Type | Valeurs | Description |
---|---|---|---|
langage | str | Langage de la tentative | |
code | str | Code de la tentative | |
tests_réussis | int | nb de tests réussis | |
publique | bool | Vrai si une tentative réussie peut être partagée |
Tentative (sous-type tentativeSys)
Une tentative de réponse à une QuestionSys.
Propriétés:
Nom | Type | Valeurs | Description |
---|---|---|---|
conteneur | str | identifiant du conteneur | |
réponse | str | Réponse à une question à solution | |
tests_réussis | int | nb de tests réussis |
Relations :
Nom | Cardinalité | Type | Description |
---|---|---|---|
résultats | 1-n | Résultat | les résultats de test |
Test
Un test de validation d’une question auquel sont soumises les solutions proposées.
Identifiant :
question_uri/numéro
Propriétés :
Nom | Type | Valeurs | Description |
---|---|---|---|
nom | str | ||
sortie_attendue | str | La sortie attendue, ou null si sortie_cachée est vrai | |
feedback_pos | str | ||
feedback_neg | str | ||
caché | bool | vrai si les entrées et sorties ont été caviardées |
TestProg (soustype de Test)
Un test de validation d’une QuestionProg auquel sont soumises les solutions proposées.
Propriétés :
Nom | Type | Valeurs | Description |
---|---|---|---|
entrée | str | L’entrée du programme ou null si sortie_cachée est vrai | |
params | str | Les paramètres du programme ou null si sortie_cachée est vrai | |
feedback_err | str |
TestSys (soustype de Test)
Un test de validation d’une QuestionSys auquel sont soumises les solutions proposées.
Propriétés :
Nom | Type | Valeurs | Description |
---|---|---|---|
validation | str | Script de validation | |
utilisateur | str | l’utilisateur du conteneur |
Token
Un token JWT.
Types de tokens
Deux types de tokens peuvent être générés :
Propriétés :
Nom | Type | Valeurs | Description |
---|---|---|---|
username | str | l’utilisateur propriétaire du token | |
création | int | timestamp à la création | |
expiration | int | timestamp d’expiration ou « +n » ou n est le nombre de secondes avant l’expiration | |
data | any | données incluses dans le token | |
ressources | [] | ressources permises par le «token ressources» | |
jwt | str | token jwt signé | |
fingerprint | str | empreinte (sha256) du contexte aléatoire du token fourni via un cookie sécurisé. | |
version | int | version de l’api ayant généré le token |
- Data
data contient un objet peuplé de n’importes quelles données utiles au destinataire du token.
- Expiration
Lorsqu’on soumet un nouveau token, l’expiration peut être exprimée de façon absolue, sous forme de timestamp en secondes depuis 1/1/1970 (ex.: 1685831340) ou de façon relative en nombre de secondes après la création du token (ex.: « +300 »)
Une date d’expiration de 0 signifie que le token n’expire jamais.
- Ressources
Les ressources sont définies par leur URI et par la méthode de requête HTTP, avec une expression rationnelle. Un token ressource peut décrire une ou plusieurs ressources.
Relations
Nom | Cardinalité | Type | Description |
---|---|---|---|
user | 1-1 | User | l’utilisateur pour lequel a été créé le token |
Utilisateur
Un utilisateur du système.
Identifiant :
username
Propriétés :
Nom | Type | Valeurs | Description |
---|---|---|---|
username | str | ||
courriel | str | ||
état | str | « inactif », « actif », « en_attente_de_validation » | |
rôle | str | « normal », « admin » | |
préférences | str | chaîne JSON décrivant les préférences UI | |
prénom | str | ||
nom | str | ||
nom_complet | str | ||
pseudo | str | ||
biographie | str | ||
occupation | str | « étudiant », « enseignant », « tuteur », « autre » | |
avatar | str |
Relations :
Nom | Cardinalité | Type | description |
---|---|---|---|
avancements | 1-n | Avancement | Liste d’avancements |
cles | 1-n | Clé | Liste de clés |
tokens | 1-n | Token | Liste de tokens en écriture seule |
Exemples
Les exemples reflètent les résultats réels sur la plus récente version de l’API disponible sur https://progression.dti.crosemont.quebec/demo/api/v1/
.
Obtenir la configuration du serveur
curl "https://progression.dti.crosemont.quebec/demo/api/v1//"
{ "data": { "type": "config", "id": "serveur", "attributes": { "version": "Progression 4.1.1()", "config": { "AUTH": { "LDAP": false, "LOCAL": false } } }, "links": { "self": "https://progression.dti.crosemont.quebec/demo/api/v1/", "inscrire": "https://progression.dti.crosemont.quebec/demo/api/v1/users" } } }
Inscription en tant qu’utilisateur jdoe
curl "https://progression.dti.crosemont.quebec/demo/api/v1//user/jdoe" -X PUT --data '{"username": "jdoe"}' -H "Content-Type: application/json"
{ "errors": [ { "title": { "type": [ "Le champ type est manquant ou ne correspond pas à un type valide" ] }, "status": 409 } ] }
Obtenir un token pour jdoe
DATA=$(cat <<EOF { "data": { "type": "token", "attributes": { "ressources": { "tout": { "url": ".*", "method": ".*" } }, "expiration": "+30" } } } EOF )
curl "https://progression.dti.crosemont.quebec/demo/api/v1//user/jdoe/tokens" -H 'Authorization: basic amRvZTo=' --data "$DATA" -H "Content-Type: application/vnd.api+json"
{ "data": { "type": "token", "id": "hcHMcNB6ZKS-lE80cqU24CGhTlJ970ze38teVbw4qDE", "attributes": { "username": "jdoe", "création": 1743453188, "expiration": 1743453218, "data": [], "jwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Impkb2UiLCJjdXJyZW50IjoxNzQzNDUzMTg4LCJleHBpcmVkIjoxNzQzNDUzMjE4LCJkYXRhIjpbXSwidmVyc2lvbiI6IjQuMS4xIiwicmVzc291cmNlcyI6eyJ0b3V0Ijp7InVybCI6Ii4qIiwibWV0aG9kIjoiLioifX19.hcHMcNB6ZKS-lE80cqU24CGhTlJ970ze38teVbw4qDE", "version": "4.1.1", "ressources": { "tout": { "url": ".*", "method": ".*" } } }, "links": { "self": "https://progression.dti.crosemont.quebec/demo/api/v1/token/hcHMcNB6ZKS-lE80cqU24CGhTlJ970ze38teVbw4qDE", "user": "https://progression.dti.crosemont.quebec/demo/api/v1/user/jdoe" } } }
Obtenir le profil de l’utilisateur authentifié jdoe
curl "https://progression.dti.crosemont.quebec/demo/api/v1//user/jdoe" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Mettre à jour les préférences de jdoe
DATA=$(cat <<EOF { "data": { "type": "user", "attributes": { "préférences": "{\"thème\": \"sombre\"}" } } } EOF )
curl "https://progression.dti.crosemont.quebec/demo/api/v1//user/jdoe" -X PATCH --data "$DATA" -H "Content-Type: application/vnd.api+json" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Obtenir la question «Les fonctions avec paramètres/Rectangle» et ses tests:
Cette question est disponible à l’URL suivant : https://progression.pages.dti.crosemont.quebec/contenu/prog_1/9bdf5f1a-489a-441f-9e6e-2c87bba58bf8/info.yml
curl "https://progression.dti.crosemont.quebec/demo/api/v1//question/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw?include=tests" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Obtenir la question «Les fonctions avec paramètres/Rectangle», ses tests et ses ébauches:
curl "https://progression.dti.crosemont.quebec/demo/api/v1//question/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw?include=tests,ebauches" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Créer l’avancement de jdoe à la question «Les fonctions avec paramètres/Rectangle»
DATA=$(cat <<EOF { "data": { "type": "avancement", "id":"aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw" } } EOF )
curl --data "$DATA" https://progression.dti.crosemont.quebec/demo/api/v1//user/jdoe/avancements -H "Content-Type: application/vnd.api+json" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Obtenir l’avancement de jdoe
pour la question «Les fonctions avec paramètres/Rectangle»
curl "https://progression.dti.crosemont.quebec/demo/api/v1//avancement/jdoe/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Obtenir l’ébauche de solution en Python pour la question «Les fonctions avec paramètres/Rectangle»
curl "https://progression.dti.crosemont.quebec/demo/api/v1//ebauche/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw/python" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Soumettre une tentative de solution à la question «Les fonctions avec paramètres/Rectangle» et récupérer les résultats
DATA=$(cat <<EOF { "data": { "type": "tentative", "attributes": { "langage":"python", "code":"# Fonction qui calcule et produit en sortie le périmètre du rectangle dont les côtés sont reçus en paramètre. À faire\ndef périmètre( une_largeur, une_longueur ):\n # -TODO\n # -VISIBLE\n\n\n # +VISIBLE\n # +TODO\n print(42)\n\n# -TODO\n# Fonction qui calcule et produit en sortie l'aire du rectangle dont les côtés sont reçus en paramètre. À faire\n# +TODO\n\n\n\n# -TODO\n# Programme principal\n# -VISIBLE\n\n# +VISIBLE\n# Entrées\nlargeur = int( input() )\nlongueur = int( input() )\n\n# Appel des fonctions, les côtés du rectangle sont transmis en paramètre. À faire\npérimètre( largeur, longueur )\n# +TODO\n\n\n# -TODO\n# -VISIBLE\n\n\n\n\n\n\n" } } } EOF )
curl --data "$DATA" https://progression.dti.crosemont.quebec/demo/api/v1//avancement/jdoe/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw/tentatives?include=resultats -H "Content-Type: application/vnd.api+json" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Obtenir une tentative de solution préalablement soumise pour la question «Les fonctions avec paramètres/Rectangle»
curl "https://progression.dti.crosemont.quebec/demo/api/v1//tentative/jdoe/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw/$TIMESTAMP" -H "Authorization: Bearer $TOKEN"
b'<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\n<html><head>\n<title>301 Moved Permanently</title>\n</head><body>\n<h1>Moved Permanently</h1>\n<p>The document has moved <a href="http://progression.dti.crosemont.quebec/tentative/jdoe/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw">here</a>.</p>\n</body></html>\n\n'
Obtenir le test numéro 0 pour la question «Les fonctions avec paramètres/Rectangle»
curl "https://progression.dti.crosemont.quebec/demo/api/v1//test/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw/0" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Obtenir un token ressource qui donne accès à un avancement de jdoe
pour la question «Les fonctions avec paramètres/Rectangle»
DATA=$(cat <<EOF { "expiration" : "+300", "data" : [], "ressources" : { "get_avancement" : { "url":"^avancement/jdoe/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw$", "method":"^GET$" } } } EOF )
curl --data "$DATA" https://progression.dti.crosemont.quebec/demo/api/v1//user/jdoe/tokens -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Créer ou mettre à jour la sauvegarde de jdoe
pour la question «Les fonctions avec paramètres/Rectangle» et un code python
DATA=$(cat <<EOF { "data": { "type": "sauvegarde", "attributes": { "langage":"python", "code": "#+TODO\nSystem.out.println('Allo le monde');\n#-TODO" } } } EOF )
curl --data "$DATA" https://progression.dti.crosemont.quebec/demo/api/v1//avancement/jdoe/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw/sauvegardes -H "Content-Type: application/vnd.api+json" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Obtenir la dernière sauvegarde de jdoe
pour la question «Les fonctions avec paramètres/Rectangle» effectuée avec le langage python
:
curl "https://progression.dti.crosemont.quebec/demo/api/v1//sauvegarde/jdoe/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw/python" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Créer une clé d’authentification pour jdoe
DATA=$(cat <<EOF { "data": { "type": "cle", "attributes": { "nom":"cléAuth$(head -c 9 /dev/urandom|base64|tr '/+' '_-')", "portée":1 } } } EOF )
curl --data "$DATA" "https://progression.dti.crosemont.quebec/demo/api/v1//user/jdoe/cles" -H "Content-Type: application/vnd.api+json" -H "Authorization: Bearer $TOKEN"
{ "erreur": "Accès interdit." }
Authentification par clé d’authentification pour jdoe
AUTH=$(echo -n "jdoe:$NOM_CLE:$SECRET" | base64 -w0)
DATA=$(cat <<EOF { "data": { "type": "token", "attributes": { "expiration" : "+300", "data" : [], "ressources" : { "get_avancement" : { "url":"^avancement/jdoe/aHR0cHM6Ly9wcm9ncmVzc2lvbi5wYWdlcy5kdGkuY3Jvc2Vtb250LnF1ZWJlYy9jb250ZW51L3Byb2dfMS85YmRmNWYxYS00ODlhLTQ0MWYtOWU2ZS0yYzg3YmJhNThiZjgvaW5mby55bWw$", "method":"^GET$" } } } } } EOF )
curl --data "$DATA" https://progression.dti.crosemont.quebec/demo/api/v1//user/jdoe/tokens -H "Content-Type: application/vnd.api+json" -H "Authorization: key $AUTH"
{ "erreur": "Accès interdit." }