Accès granulaire avec target
Le paramètre target permet d’ouvrir un cours, un exercice ou une autre page
précise après l’authentification via une landing ProxyNinja. La ressource doit
lire ce paramètre et réaliser la navigation finale.
Construire le lien
Section intitulée « Construire le lien »Privilégiez un chemin relatif à la racine de votre ressource, comme /cours/42.
Encodez la valeur complète une seule fois :
const target = '/cours/42?chapter=2#exercise';const landing = new URL('https://landing.proxyninja.fr/votre-ressource-pronote');landing.searchParams.set('target', target); // encode automatiquement la valeurconst link = landing.href;Lien obtenu :
https://landing.proxyninja.fr/votre-ressource-pronote?target=%2Fcours%2F42%3Fchapter%3D2%23exerciseRemplacez votre-ressource-pronote par le slug communiqué pour votre intégration.
Vous pouvez aussi concaténer '?target=' + encodeURIComponent(target), mais
n’appliquez pas encodeURIComponent avant searchParams.set : cela
encoderait deux fois la valeur. Les &, ? et # de la destination font partie
de target, pas des paramètres de la landing.
Ce que reçoit votre ressource
Section intitulée « Ce que reçoit votre ressource »ProxyNinja ajoute target à la redirectUri configurée pour le slug, puis
conserve cette URI pendant le parcours d’authentification de la landing.
Exemple générique, avec le point d’entrée https://ressource.example/api/auth/sso :
https://ressource.example/api/auth/sso?target=%2Fcours%2F42%3Fchapter%3D2%23exerciseVotre parseur de query string restitue alors :
/cours/42?chapter=2#exercise| Cas | Contrat de propagation |
|---|---|
target absent ou vide |
La redirectUri reste inchangée ; conserver votre accueil habituel. |
Chemin /cours/42 ou cours/42 |
Transmis tel quel ; la ressource choisit sa base de résolution. |
| URL absolue | Transmise telle quelle ; la ressource valide son origine avant de l’utiliser. |
Paramètres déjà présents dans la redirectUri |
Conservés ; un ancien paramètre target est remplacé. |
Plusieurs paramètres target sur la landing |
La première valeur est utilisée ; ne générez qu’un seul paramètre. |
target est un paramètre de navigation fourni par l’utilisateur. Il ne
constitue ni un attribut d’identité, ni une preuve d’autorisation, ni une
revendication de jeton. Le domaine et le chemin du point d’entrée configuré
restent les mêmes. Ce contrat concerne la landing classique ; le lancement
LTI utilise son propre target_link_uri.
Depuis un lien OpenAthens (WAYFless)
Section intitulée « Depuis un lien OpenAthens (WAYFless) »Avec OpenAthens, la destination voyage dans target_link_uri. OpenAthens
renvoie l’usager vers l’URL de connexion de l’application, c’est-à-dire la
landing ProxyNinja, avec iss et target_link_uri. Sur les routes que
ProxyNinja a configurées pour cela, la landing reprend target_link_uri
comme target, et votre ressource la reçoit exactement comme ci-dessus.
- Accepté : un chemin relatif commençant par un seul
/(/cours/42), transmis tel quel ; ou une URL absoluehttpssur une origine déclarée pour la route. - Écarté :
cours/42,//hote,/%2F%2Fhote,/\hote, toute autre origine. L’usager est alors connecté normalement et arrive sur votre accueil.
Pour une route non configurée, target_link_uri est ignoré : la connexion
fonctionne, sans retour à la page précise. Les liens que vos usagers partagent
entre collègues d’un même établissement sont décrits dans
Liens partageables.
Instrumenter le point d’entrée de la ressource
Section intitulée « Instrumenter le point d’entrée de la ressource »1. Lire et valider la destination
Section intitulée « 1. Lire et valider la destination »Lisez target dès l’arrivée sur votre point d’entrée SSO, avant toute
redirection supplémentaire. Utilisez le parseur de votre framework
(URLSearchParams, $request->query('target'), $_GET['target']…) et
n’effectuez pas de second décodage manuel.
Résolvez les chemins relatifs contre une origine fixe de votre application,
pas contre l’hôte de la landing ni un en-tête Host non validé. La politique
conseillée est de n’accepter que vos propres pages de contenu. Rejetez les
origines externes, les schémas autres que HTTPS, les URLs avec identifiants et
les destinations vers vos endpoints de login/logout/callback.
Exemple JavaScript exécutable, à adapter à vos routes :
const RESOURCE_ORIGIN = 'https://ressource.example';const DEFAULT_DESTINATION = RESOURCE_ORIGIN + '/';
function validateTarget(raw) { if (raw == null || raw === '') return DEFAULT_DESTINATION; if (typeof raw !== 'string' || raw.trim() !== raw) return null; if (/[\u0000-\u0020\u007f\\]/.test(raw) || raw.startsWith('//')) return null;
let destination; try { destination = new URL(raw, RESOURCE_ORIGIN + '/'); } catch { return null; } if (destination.origin !== RESOURCE_ORIGIN) return null; if (destination.username || destination.password) return null;
// Exemple : seules les pages /cours/:id et /exercices/:id sont admises. // Adaptez cette liste à vos contenus ; excluez les routes d'authentification. if (!/^\/(cours|exercices)\/[A-Za-z0-9_-]+$/.test(destination.pathname)) return null; return destination.href; // URL absolue normalisée sur notre origine}
const incoming = new URL(requestUrl, RESOURCE_ORIGIN); // URL de la requête entranteconst values = incoming.searchParams.getAll('target');const destination = values.length > 1 ? null : validateTarget(values[0]);// null : répondre 400, ou choisir explicitement un accueil sûr.Le filtre de routes est une première validation. Vos contrôleurs doivent aussi
vérifier que l’utilisateur a le droit de consulter le contenu demandé. Ne
faites pas de redirection directe avec la valeur brute de target : cela
créerait une redirection ouverte (OAuth 2.0, section 10.15).
2. Conserver target pendant votre authentification
Section intitulée « 2. Conserver target pendant votre authentification »Une session ProxyNinja n’est pas une session locale de votre application. À chaque arrivée sur le point d’entrée d’authentification, effectuez une nouvelle demande d’identité auprès de ProxyNinja, même si une session locale existe déjà. Ne court-circuitez pas cette entrée avec une identité ou des attributs conservés en cache : ils peuvent avoir changé depuis la connexion précédente. C’est particulièrement important avec Pronote, et cette règle s’applique aussi aux autres sources d’identité.
Après validation de la réponse, mettez à jour les attributs et les droits locaux, puis renouvelez la session applicative avant d’ouvrir la destination. Une nouvelle transaction d’authentification n’impose pas nécessairement une nouvelle saisie d’identifiants : le SSO peut rester transparent. La navigation ordinaire dans la ressource peut continuer à utiliser la session locale ; c’est l’arrivée sur l’entrée SSO qui déclenche ce renouvellement. Voir le parcours d’authentification.
Enregistrez la destination validée côté serveur dans la transaction de
connexion avant de partir vers le fournisseur d’identité. En OIDC, associez-la
au state aléatoire produit et vérifié par votre bibliothèque, avec le contexte
PKCE/nonce habituel. Conservez les garanties de la bibliothèque ; ne remplacez
pas state par l’URL de destination.
Utilisez une transaction par connexion, liée à la session du navigateur, avec
expiration et consommation unique. Un champ global session.target peut être
écrasé quand deux onglets ouvrent deux contenus différents.
Schéma d’intégration, en pseudo-code (les opérations d’authentification sont celles de votre bibliothèque, pas une API ProxyNinja à recopier) :
À l'entrée SSO de la ressource : destination = valider(target), ou accueil si absent si destination invalide : refuser la requête même si une session locale existe déjà : créer une nouvelle transaction d'authentification liée au navigateur stocker destination dans cette transaction côté serveur demander à nouveau l'identité avec le contexte sécurisé de la bibliothèque
Au callback de la ressource : valider la réponse et la transaction avec la bibliothèque si erreur ou transaction absente/expirée : arrêter le parcours récupérer la destination depuis la transaction validée, pas depuis le callback actualiser les attributs et les droits, renouveler la session locale consommer la transaction vérifier les droits sur le contenu rediriger vers la destination sans recopier code, state ou jetonsMême si la landing ajoute un code à votre URL d’entrée, n’échangez pas un
code émis pour le client de la landing avec les identifiants de votre propre
client. Démarrez une nouvelle transaction de votre ressource à chaque entrée SSO ; la session
SSO déjà établie peut éviter une nouvelle saisie d’identifiants.
3. Garder un callback OIDC cohérent
Section intitulée « 3. Garder un callback OIDC cohérent »Préférez un callback fixe pour la transaction OIDC de votre ressource :
stockez la destination côté serveur au lieu de modifier ce callback à chaque
cours. Si votre intégration utilise effectivement un callback avec target
dans sa query string, la redirect_uri de l’échange de code doit être
identique à celle envoyée lors de l’autorisation, y compris target ; elle
n’inclut pas les paramètres de réponse code et state.
(OAuth 2.0, section 4.1.3)
Faites valider avec ProxyNinja l’acceptation de la nouvelle URL de retour de la
landing par son client Keycloak. L’ajout de target ne justifie pas d’autoriser
tous les domaines ou tous les chemins de callback.
4. Ouvrir le contenu après création de session
Section intitulée « 4. Ouvrir le contenu après création de session »Redirigez vers la destination validée une fois l’identité vérifiée et la session locale créée. Le contenu applique ses contrôles d’accès habituels. Si le cours est inexistant ou interdit, affichez votre réponse 404/403 habituelle ; ne renvoyez pas automatiquement vers la landing, ce qui pourrait créer une boucle.
Recette avant activation
Section intitulée « Recette avant activation »| Test | Résultat attendu |
|---|---|
Lien sans target |
Parcours et accueil existants inchangés. |
/cours/42 sans session locale |
Authentification, création de session, puis cours 42. |
/cours/42 avec session locale |
Nouvelle demande d’identité, attributs actualisés, session renouvelée, puis cours 42. |
| Attributs Pronote modifiés depuis la connexion précédente | À la prochaine arrivée sur l’entrée SSO, les nouveaux attributs et droits remplacent les valeurs locales précédentes. |
/cours/42?chapter=2#exercise |
Paramètres et ancre conservés, sans double décodage. |
| URL absolue sur votre origine | Acceptée si le chemin est autorisé. |
URL externe, //autre.example, javascript:… |
Refus, sans redirection externe. |
| Deux onglets avec deux cours | Chaque transaction conserve sa propre destination. |
| Connexion refusée ou transaction expirée | Aucun accès au contenu ni utilisation d’une ancienne destination. |
| Contenu interdit à l’utilisateur | Refus d’accès, même avec une session valide. |
Vérifiez les deux étapes : target est présent dans l’URL reçue par votre point
d’entrée, puis il est encore disponible après votre retour d’authentification.
N’insérez ni secret ni donnée personnelle dans target : une URL peut apparaître
dans l’historique et les journaux d’accès.