Aller au contenu

Guide d'intégration

Ce guide décrit ce que vous devez fournir et mettre en œuvre pour intégrer votre ressource à ProxyNinja : la configuration d’authentification (OIDC, SAML2, CAS3 ou LTI 1.3), le point d’entrée fonctionnel (vérification de session), et des exemples de code par stack (PHP, Laravel, Node), y compris la déconnexion.

Élément OIDC SAML2 CAS3 LTI 1.3
Identifiant client client_id + client_secret entityID du SP + certificat nom de service client_id de l’outil (+ clé publique / JWKS si services LTI)
URL de retour redirect_uri (callback) ACS (Assertion Consumer Service) service URL target_link_uri (URL de lancement)
URL de login (point d’entrée) initiate_login_uri (initiation OIDC tierce)
URL de logout (back-channel / SLO) ✅ (back-channel OIDC)

Vous fournissez ces éléments pour la préproduction et la production. Voir le questionnaire, sections B et F.

Rappel des bases realm (<EDITEUR> = votre realm = le slug de votre tenant) :

Environnement Modèle de déploiement Base realm
Préproduction instance partagée https://preprod-proxy.gar.ninja/realms/<EDITEUR>
Production instance dédiée par éditeur https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>

ProxyNinja est l’OP (OpenID Provider). Tout se découvre depuis le document .well-knownne codez pas les endpoints en dur, lisez-les depuis la découverte.

  • Issuer : https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>
  • Découverte : …/realms/<EDITEUR>/.well-known/openid-configuration
  • Endpoints (exposés par la découverte) :
    • authorization_endpoint : …/protocol/openid-connect/auth
    • token_endpoint : …/protocol/openid-connect/token
    • userinfo_endpoint : …/protocol/openid-connect/userinfo
    • end_session_endpoint : …/protocol/openid-connect/logout
    • jwks_uri : …/protocol/openid-connect/certs
  • Flow : Authorization Code + PKCE (S256).
  • Scopes : openid (obligatoire) profile email, plus les scopes d’attributs établissement si activés sur votre realm.
  • Authentification client : client_secret_basic (ou client_secret_post).

ProxyNinja est l’IdP ; votre application est le SP.

  • Métadonnées IdP (à consommer) : https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>/protocol/saml/descriptor
  • SSO / SLO : https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>/protocol/saml
  • À fournir (métadonnées SP) : entityID, URL ACS (binding HTTP-POST), URL SLO, format de NameID souhaité, et le certificat de signature du SP.
  • Indiquez si vous exigez des assertions signées/chiffrées (recommandé : assertions signées).

ProxyNinja expose le protocole CAS (extension CAS de Keycloak). Vous agissez en client CAS.

  • Base CAS : https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>/protocol/cas
    • login : …/protocol/cas/login?service=<votre-service>
    • validate (CAS3, avec attributs) : …/protocol/cas/p3/serviceValidate
    • logout : …/protocol/cas/logout
  • À fournir : l’URL service (votre point d’entrée) et l’URL de logout pour la propagation.

ProxyNinja est la plateforme LTI (rôle Platform, celui d’un LMS) ; votre ressource est l’outil (rôle Tool). L’utilisateur est authentifié en amont (GAR, ENT…) par ProxyNinja, puis lancé vers votre outil avec un id_token signé qui porte les revendications LTI.

Choisissez LTI 1.3 si votre ressource est déjà un outil LTI (elle est distribuée via Moodle, Brightspace, Canvas…) : vous réutilisez la brique que vous avez, au lieu d’ajouter un client OIDC.

Nous vous fournissons :

  • Issuer de la plateforme (iss) : https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>
  • client_id de votre outil et deployment_id (identifiant de déploiement)
  • Endpoint d’autorisation (lancement OIDC) : …/realms/<EDITEUR>/protocol/openid-connect/auth
  • JWKS de la plateforme (pour valider le id_token de lancement) : …/realms/<EDITEUR>/protocol/openid-connect/certs
  • Endpoint de lancement de la plateforme : …/realms/<EDITEUR>/lti-platform/launch

Vous nous fournissez :

  • initiate_login_uri — votre endpoint d’initiation OIDC tierce (third-party initiated login), appelé en premier par la plateforme.
  • target_link_uri — l’URL de lancement de la ressource (elle doit aussi figurer dans vos redirect URIs valides).
  • La clé publique / l’URL JWKS de votre outil, uniquement si vous consommez les services LTI Advantage (voir plus bas) : ils exigent que l’outil signe ses propres jetons client_credentials.

Paramètres du flux (ce sont ceux de la spécification LTI 1.3, pas un choix ProxyNinja) : response_type=id_token, response_mode=form_post, scope=openid, prompt=none, plus les state / nonce que vous devez valider. Côté client Keycloak, cela se traduit par un flux implicite activé et le flux standard désactivé — donc pas d’échange de code ni d’appel /token pour le lancement : tout arrive dans le id_token posté sur votre target_link_uri.

Revendications reçues dans le id_token (préfixe https://purl.imsglobal.org/spec/lti/claim/) :

Revendication Contenu
message_type · version LtiResourceLinkRequest · 1.3.0
deployment_id Le deployment_id que nous vous avons attribué — à vérifier
target_link_uri L’URL de lancement demandée
roles Rôles IMS, dérivés de l’attribut GAR profil (voir ci-dessous)
context Contexte du lancement (id, label, title, type)
resource_link Lien de ressource (id, title, description)
tool_platform Identité de la plateforme (name, version, guid, product_family_code)
custom Paramètres personnalisés autorisés : id_ressource, id_etab, sso_id

Rôles. Le profil national GAR est traduit en URI de rôle IMS avant émission — votre outil lit roles, pas profil :

Profil GAR Rôle LTI
National_1, Enseignant …/vocab/lis/v2/membership#Instructor
National_2, Eleve …/vocab/lis/v2/membership#Learner
National_3 …/vocab/lis/v2/membership/Instructor#TeachingAssistant
National_ENTDirecteur …/vocab/lis/v2/institution/person#Administrator
National_ENTParent …/vocab/lis/v2/membership#Mentor

Le rôle par défaut, quand le profil est absent ou inconnu, est Learner. Traitez donc roles comme potentiellement dégradé et n’accordez jamais de privilège d’enseignant sur la seule absence de valeur.

Services LTI Advantage exposés par la plateforme (optionnels, activés au cas par cas) :

Service Endpoint
NRPS (Names and Role Provisioning) …/realms/<EDITEUR>/lti-services/memberships
AGS (Assignment and Grade Services) …/realms/<EDITEUR>/lti-services/lineitems
Deep Linking …/realms/<EDITEUR>/lti-services/deep-linking

Ce cas est l’inverse du précédent et ne change rien à votre intégration : c’est une question de source d’identité, pas de protocole côté ressource.

Quand les utilisateurs n’arrivent pas du GAR mais d’un LMS (Brightspace/D2L, Moodle, ENT compatible LTI), ProxyNinja se déclare comme outil LTI auprès de ce LMS et le rebranche comme fournisseur d’identité du realm — exactement comme il branche le GAR, École Directe ou Pronote. Votre ressource, elle, continue de parler OIDC / SAML2 / CAS3 (ou LTI) sans modification.

À enregistrer dans le LMS (ProxyNinja, côté outil) — <alias> est l’alias de l’IDP, lti13 par défaut :

Élément Valeur
Login / OIDC initiation URL https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>/broker/<alias>/initiate
Redirect / launch URL https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>/broker/<alias>/endpoint
Public keyset (JWKS) https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>/protocol/openid-connect/certs

À nous transmettre (côté plateforme, fourni par le LMS) : son issuer (iss), son endpoint d’autorisation, son URL JWKS, le client_id qu’il attribue à ProxyNinja et le deployment_id. Brightspace / D2L bénéficie d’un traitement dédié (paramètres d2l_user_id, d2l_org_unit_id, d2l_role).

Le cœur de l’intégration côté éditeur est un point d’entrée qui implémente une seule décision :

Requête entrante sur le point d'entrée
Ai-je une session locale valide ?
┌────┴─────┐
OUI NON
│ │
▼ ▼
Servir la Demander l'authentification à ProxyNinja
ressource (OIDC /authorize · SAML AuthnRequest · CAS /login)
Retour (code / ticket) → échange jetons → récupérer les attributs
Créer la session locale → servir la ressource

Comme l’utilisateur arrive déjà authentifié depuis le médiacentre, la demande à ProxyNinja est en général transparente (pas de re-saisie). Voir le parcours de bout en bout.

Bibliothèques recommandées (voir le récapitulatif en bas de page) :

OIDC — point d’entrée + récupération des attributs

Section intitulée « OIDC — point d’entrée + récupération des attributs »
Fenêtre de terminal
composer require jumbojett/openid-connect-php
<?php
require 'vendor/autoload.php';
use Jumbojett\OpenIDConnectClient;
session_start();
// --- Point d'entrée : ai-je une session locale ? ---
if (!empty($_SESSION['user'])) {
render_resource($_SESSION['user']); // OUI → on sert la ressource
exit;
}
// NON → on demande l'identité à ProxyNinja.
$oidc = new OpenIDConnectClient(
'https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>', // issuer (sans slash final)
'votre-client-id',
'votre-client-secret'
);
$oidc->setRedirectURL('https://votre-ressource.fr/callback');
$oidc->addScope(['openid', 'profile', 'email']);
$oidc->setCodeChallengeMethod('S256'); // PKCE recommandé
$oidc->authenticate(); // redirige vers ProxyNinja, puis revient ici
$claims = $oidc->requestUserInfo(); // récupération des attributs (/userinfo)
$_SESSION['user'] = (array) $claims;
$_SESSION['id_token'] = $oidc->getIdToken();
$_SESSION['access_token'] = $oidc->getAccessToken();
render_resource($_SESSION['user']);

ProxyNinja notifie votre ressource lorsqu’une session doit être fermée (POST d’un logout_token JWT). Votre endpoint doit : (1) valider le logout_token (signature via le jwks_uri du realm), (2) extraire sub et/ou sid, (3) détruire la session locale correspondante — en quelques secondes, sans attendre l’expiration d’un jeton.

POST /backchannel_logout HTTP/1.1
Host: votre-ressource.fr
Content-Type: application/x-www-form-urlencoded
logout_token=eyJhbGci....eyJpc3Mi....T3BlbklE..
<?php
require 'vendor/autoload.php';
use Jumbojett\OpenIDConnectClient;
// Endpoint POST /backchannel_logout
$logoutToken = $_POST['logout_token'] ?? '';
$oidc = new OpenIDConnectClient(
'https://<EDITEUR>-auth.proxyninja.fr/realms/<EDITEUR>',
'votre-client-id',
'votre-client-secret'
);
// Valide la signature + les claims (iss, aud, events, sid/sub) via le JWKS du realm
if ($oidc->verifyLogoutToken($logoutToken)) {
$sid = $oidc->getSidFromBackChannel(); // ou claim `sub`
destroy_local_sessions_for($sid); // votre logique (table sid → session)
http_response_code(200);
} else {
http_response_code(400);
}
Protocole PHP Laravel Node.js
OIDC jumbojett/openid-connect-php Socialite + socialiteproviders/keycloak (ou Kovah/laravel-socialite-oidc) openid-client (+ openid-client/passport)
SAML2 onelogin/php-saml (ou simpleSAMLphp en mode SP) aacotroneo/laravel-saml2 (basé sur OneLogin) @node-saml/passport-saml (ou samlify)
CAS3 apereo/phpCAS apereo/phpCAS (intégré manuellement) connect-cas2 / client CAS dédié
LTI 1.3 packbackbooks/lti-1p3-tool (ou celtic-lti/lti) packbackbooks/lti-1p3-tool (intégré manuellement) ltijs
  1. Stockage sécurisé des jetons : jamais en clair ; cookies de session serveur (HttpOnly, Secure, SameSite) ou store serveur.
  2. PKCE (S256) systématique sur le flow OIDC Authorization Code.
  3. Découverte .well-known : lisez les endpoints depuis la découverte, ne les codez pas en dur.
  4. Déconnexion en quelques secondes : propagez le back-channel logout immédiatement ; n’attendez jamais l’expiration d’un jeton.
  5. Validez toujours la signature des jetons (id_token, logout_token) via le jwks_uri du realm — et, en LTI 1.3, également le nonce (usage unique) et le deployment_id.