Aller au contenu principal

Liens authentifiés

Cette documentation décrit comment intégrer votre application partenaire avec téo grâce aux liens authentifiés.

Vue d'ensemble

téo permet de créer des liens authentifiés vers votre application. Lorsqu'un utilisateur clique sur un lien partenaire dans téo, il est redirigé vers votre application avec un token JWT (JSON Web Token) signé cryptographiquement. Ce token contient les informations de contexte (dossier, utilisateur) et permet d'authentifier la requête.

Avantages

  • Sécurité : Tokens signés avec algorithme ES256, impossibles à falsifier
  • Contexte : Le token contient les informations du dossier et de l'utilisateur
  • Expiration : Tokens à durée de vie limitée (5 minutes par défaut)
  • Standard : Basé sur les standards JWT (RFC 7519) et JWKS

Enrichir les données via l'API

Le JWT contient les identifiants essentiels (UUID du dossier, ID utilisateur, etc.). Votre application peut utiliser ces identifiants pour appeler l'API téo et récupérer des informations complémentaires.

Le JWT n'est pas un token d'accès API

Le JWT partenaire sert uniquement à transmettre le contexte depuis téo. Pour appeler l'API téo, vous devez vous authentifier séparément avec vos identifiants OAuth2 (CLIENT_ID, CLIENT_SECRET) comme décrit dans la documentation d'authentification.

Par exemple, avec le dossierId contenu dans le JWT, vous pouvez :

  1. Vous authentifier à l'API avec vos identifiants OAuth2
  2. Appeler GET /api/production/dossiers/{dossierId}
  3. Récupérer les informations complètes : nom, prénom, email, historique des séances, documents...
Combiner JWT et API

Le JWT vous donne le contexte (quel dossier, quel utilisateur). L'API, avec vos propres identifiants, vous permet d'enrichir ce contexte avec toutes les données dont vous avez besoin.

Devenir partenaire

  1. Testez votre intégration avec l'environnement sandbox, accessible à tous sans demande préalable
  2. Demandez votre accès partenaire une fois vos tests validés (voir procédure)

Comment ça fonctionne

Une fois votre intégration configurée, un lien vers votre application apparaît directement dans les dossiers téo. Lorsqu'un utilisateur clique sur ce lien :

  1. téo génère automatiquement un token JWT signé contenant les informations du dossier
  2. L'utilisateur est redirigé vers votre application avec ce token
  3. Votre application vérifie le token et authentifie l'utilisateur

L'utilisateur accède ainsi à votre application dans le contexte du dossier qu'il consultait, sans avoir à se réauthentifier.

Flux d'authentification

Format du JWT

Structure

Le JWT est composé de trois parties séparées par des points : header.payload.signature

{
"alg": "ES256",
"typ": "JWT",
"kid": "{key_id}"
}
ChampDescription
algAlgorithme de signature (ES256)
typType de token (toujours JWT)
kidIdentifiant de la clé utilisée pour la signature

Payload (Claims)

ClaimTypeDescription
issstringÉmetteur du token (instance téo)
substringSujet principal (UUID du dossier)
dossierIdstringUUID du dossier
dossierIidintegerIdentifiant interne (numérique) du dossier
userIdstringUUID de l'utilisateur connecté
userEmailstringEmail de l'utilisateur connecté
slugstringIdentifiant de l'instance téo
tenantIdstringIdentifiant du tenant
iatintegerTimestamp de création (Unix)
expintegerTimestamp d'expiration (Unix)
Claims personnalisés

Des claims supplémentaires peuvent être ajoutés selon les besoins de votre intégration. Contactez-nous pour en discuter.

Exemple de payload

{
"iss": "demo.teo-online.net",
"sub": "a2352f07-0439-499b-bb87-6e516d4e177c",
"dossierId": "a2352f07-0439-499b-bb87-6e516d4e177c",
"dossierIid": 12345,
"userId": "f011b0ab-5994-102b-b457-34c438cd5d6b",
"userEmail": "[email protected]",
"slug": "demo",
"tenantId": "f011b0ab-5994-102b-b457-34c438cd5d6b",
"iat": 1737820800,
"exp": 1737821100
}

Vérification du JWT

Endpoint JWKS

Les clés publiques pour vérifier les signatures sont disponibles via l'endpoint JWKS standard :

GET https://auth.teoapp.fr/.well-known/jwks.json
Cache recommandé

Les clés publiques changent rarement. Nous recommandons de les mettre en cache pendant 24 heures pour optimiser les performances.

Endpoint clé publique

Pour récupérer une clé spécifique par son identifiant :

GET https://auth.teoapp.fr/api/jwt/public-key?kid={kid}

Implémentation

Exemple PHP

<?php
use Firebase\JWT\JWT;
use Firebase\JWT\JWK;

// 1. Récupérer le token depuis l'URL
$token = $_GET['teo_jwt'] ?? null;

if (!$token) {
http_response_code(400);
die('Token manquant');
}

// 2. Récupérer les clés publiques (avec cache)
function getJwks(): array
{
$cacheFile = sys_get_temp_dir() . '/teo_jwks.json';
$cacheTime = 86400; // 24 heures

if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $cacheTime) {
return json_decode(file_get_contents($cacheFile), true);
}

$jwks = file_get_contents('https://auth.teoapp.fr/.well-known/jwks.json');
file_put_contents($cacheFile, $jwks);

return json_decode($jwks, true);
}

// 3. Vérifier et décoder le JWT
try {
$jwks = getJwks();
$keys = JWK::parseKeySet($jwks);

$decoded = JWT::decode($token, $keys);

// 4. Utiliser les données
$dossierId = $decoded->dossierId;
$dossierIid = $decoded->dossierIid;
$userEmail = $decoded->userEmail;
$slug = $decoded->slug;

// Votre logique métier...

} catch (Exception $e) {
http_response_code(401);
die('Token invalide: ' . $e->getMessage());
}

Dépendance requise :

composer require firebase/php-jwt

Exemple Node.js

const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

// Configuration du client JWKS
const client = jwksClient({
jwksUri: 'https://auth.teoapp.fr/.well-known/jwks.json',
cache: true,
cacheMaxAge: 86400000 // 24 heures
});

// Fonction pour récupérer la clé
function getKey(header, callback) {
client.getSigningKey(header.kid, (err, key) => {
if (err) return callback(err);
callback(null, key.getPublicKey());
});
}

// Middleware Express
function verifyTeoToken(req, res, next) {
const token = req.query.teo_jwt;

if (!token) {
return res.status(400).json({ error: 'Token manquant' });
}

jwt.verify(token, getKey, { algorithms: ['ES256'] }, (err, decoded) => {
if (err) {
return res.status(401).json({ error: 'Token invalide' });
}

req.teoUser = decoded;
next();
});
}

// Utilisation
app.get('/callback', verifyTeoToken, (req, res) => {
const { dossierId, dossierIid, userEmail } = req.teoUser;
// Votre logique métier...
});

Dépendances requises :

npm install jsonwebtoken jwks-rsa

Exemple Python

import jwt
import requests
from functools import lru_cache

@lru_cache(maxsize=1)
def get_jwks():
"""Récupère et met en cache les clés publiques."""
response = requests.get('https://auth.teoapp.fr/.well-known/jwks.json')
return response.json()

def get_public_key(token):
"""Récupère la clé publique correspondant au token."""
header = jwt.get_unverified_header(token)
jwks = get_jwks()

for key in jwks['keys']:
if key['kid'] == header['kid']:
return jwt.algorithms.RSAAlgorithm.from_jwk(key)

raise Exception('Clé non trouvée')

def verify_teo_token(token):
"""Vérifie et décode un token téo."""
try:
public_key = get_public_key(token)
decoded = jwt.decode(
token,
public_key,
algorithms=['ES256']
)
return decoded
except jwt.ExpiredSignatureError:
raise Exception('Token expiré')
except jwt.InvalidTokenError as e:
raise Exception(f'Token invalide: {e}')

# Utilisation (Flask)
@app.route('/callback')
def callback():
token = request.args.get('teo_jwt')

if not token:
return {'error': 'Token manquant'}, 400

try:
data = verify_teo_token(token)
dossier_id = data['dossierId']
user_email = data['userEmail']
# Votre logique métier...
except Exception as e:
return {'error': str(e)}, 401

Dépendances requises :

pip install PyJWT requests cryptography

Bonnes pratiques de sécurité

Validation obligatoire

  1. Vérifier la signature : Toujours valider la signature cryptographique du JWT
  2. Vérifier l'expiration : Le claim exp doit être dans le futur
  3. Vérifier l'émetteur : Le claim iss doit correspondre à une instance téo autorisée

Recommandations

  • HTTPS obligatoire : Toutes les communications doivent utiliser HTTPS
  • Ne jamais faire confiance aux données non vérifiées : Valider le JWT avant d'utiliser ses données
  • Logger les erreurs : Conserver une trace des tentatives d'authentification échouées
  • Limiter les émetteurs : Maintenir une liste blanche des instances téo autorisées
// Exemple de vérification de l'émetteur
$allowedIssuers = [
'client1.teo-online.net',
'client2.teo-online.net',
];

if (!in_array($decoded->iss, $allowedIssuers)) {
throw new Exception('Émetteur non autorisé');
}

Environnement de test (Sandbox)

Un environnement de test est disponible pour valider votre intégration avant la mise en production.

Interface de test interactive

Une interface web est disponible pour générer des tokens de test et valider votre implémentation :

Accéder à l'interface de test Sandbox

Cette interface vous permet de :

  • Générer des tokens JWT avec des données fictives
  • Tester votre URL de callback
  • Visualiser le payload décodé
  • Valider votre implémentation sans dossier réel

API de test

Vous pouvez également générer des tokens de test par API :

POST https://{instance}.teo-online.net/next/app.php/api/authenticated-link/sandbox/token
Content-Type: application/json

{
"callback_url": "https://votre-app.com/callback",
"ttl": 300
}

Réponse :

{
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 300,
"jwks_uri": "https://auth.teoapp.fr/.well-known/jwks.json",
"test_url": "https://votre-app.com/callback?teo_jwt=..."
}

Format identique à la production

Les tokens sandbox ont exactement le même format que les tokens de production. Cela vous permet de tester votre implémentation dans des conditions réelles.

Les seules différences sont les valeurs des données, qui sont fictives :

ChampValeur sandbox
dossierId00000000-0000-0000-0000-000000000001
dossierIid1
Validation complète

Puisque le format est identique, vous pouvez valider l'intégralité de votre code de parsing et de vérification de signature avec les tokens sandbox.

Demander un accès partenaire

Une fois vos tests validés, contactez-nous pour la mise en production :

  1. Rendez-vous sur le système de tickets
  2. Créez un ticket "Demande d'intégration partenaire"
  3. Joignez :
    • Le nom de votre application
    • L'URL de callback de production
    • Les résultats de vos tests sandbox
  4. Notre équipe configurera votre accès et vous fournira votre identifiant partenaire

Résolution de problèmes

Erreurs courantes

ErreurCauseSolution
Token expiréLe token a dépassé sa durée de validitéLes tokens expirent après 5 minutes. L'utilisateur doit retourner sur téo.
Signature invalideClé publique incorrecte ou token altéréVérifiez que vous utilisez les bonnes clés JWKS
Clé non trouvéeLe kid du token ne correspond à aucune cléVidez le cache des clés et réessayez
Émetteur non autoriséL'iss ne fait pas partie de votre liste blancheAjoutez l'émetteur à votre configuration

Debug

Pour déboguer un token, vous pouvez utiliser jwt.io :

  1. Collez le token dans le décodeur
  2. Vérifiez les claims dans le payload
  3. Attention : ne faites pas confiance aux données sans vérifier la signature !