Intégrer Pro Santé Connect : le guide technique complet (2026)

Antoine Auffray

07/04/2026

Pro Santé Connect est obligatoire depuis janvier 2023 pour tout service numérique en santé. Pourtant, en cherchant un guide d'intégration technique en français, on ne trouve que la documentation officielle de l'ANS, dense et dispersée sur plusieurs portails.

Chez Bob le développeur, on intègre PSC sur des projets e-santé depuis plusieurs années. Cet article rassemble tout ce qu'on aurait aimé trouver à l'époque : le flow OIDC complet, les endpoints exacts (sandbox et production), le parsing des claims RPPS, une implémentation NestJS prête à l'emploi, et surtout les pièges qui font perdre des semaines quand on ne les connaît pas.

L'essentiel en 30 secondes :

  • PSC utilise OpenID Connect (Authorization Code Flow) avec des spécificités santé
  • L'endpoint Authorize a un host différent des autres endpoints
  • Le paramètre acr_values doit valoir eidas1 (pas eidas2)
  • Le numéro RPPS se trouve dans le SubjectNameID, préfixé par 8
  • La vérification RPPS via l'API Annuaire Santé est indispensable

Qu'est-ce que Pro Santé Connect et pourquoi c'est obligatoire ?

Pro Santé Connect (PSC) est le fédérateur d'identité sectoriel de la santé en France. Opéré par l'Agence du Numérique en Santé (ANS), il permet aux professionnels de santé de s'authentifier sur les services numériques en utilisant leurs moyens d'identification professionnels : la carte CPS physique, l'application mobile e-CPS, ou des certificats logiciels pour les échanges serveur-à-serveur.

PSC se distingue de FranceConnect sur un point fondamental : FranceConnect authentifie les citoyens (vos patients), PSC authentifie les professionnels de santé (médecins, pharmaciens, infirmiers). Les deux reposent sur OpenID Connect, mais PSC ajoute des claims spécifiques au secteur santé, notamment le numéro RPPS et le rôle professionnel.

Depuis l'arrêté du 4 avril 2022, l'intégration de PSC est obligatoire pour les services numériques en santé nationaux et territoriaux, ainsi que pour les services locaux fortement intégrés au système de santé. Si vous développez une application de téléconsultation, un logiciel de gestion de cabinet ou une plateforme de coordination des soins, PSC n'est pas une option.


Le flow OpenID Connect de PSC en 11 étapes

PSC implémente le standard OpenID Connect 1.0 avec un Authorization Code Flow. Le processus est similaire à ce que vous connaissez avec FranceConnect ou tout autre provider OIDC, mais avec quelques spécificités à respecter.

Diagramme du flow complet

Navigateur          Votre Backend           PSC (ANS)          Annuaire Santé
    │                     │                     │                     │
    │  1. Clic "Se        │                     │                     │
    │  connecter PSC"     │                     │                     │
    │────────────────────>│                     │                     │
    │                     │  2. Redirect avec   │                     │
    │                     │  state + nonce      │                     │
    │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─│────────────────────>│                     │
    │                     │                     │                     │
    │  3. Choix CPS ou e-CPS                    │                     │
    │  4. Authentification du médecin           │                     │
    │                     │                     │                     │
    │  5. Callback avec   │                     │                     │
    │  ?code=xxx&state=yyy│                     │                     │
    │────────────────────>│                     │                     │
    │                     │  6. Échange code    │                     │
    │                     │  → access_token     │                     │
    │                     │────────────────────>│                     │
    │                     │<────────────────────│                     │
    │                     │                     │                     │
    │                     │  7. GET /userinfo   │                     │
    │                     │────────────────────>│                     │
    │                     │<────────────────────│                     │
    │                     │  8. Claims RPPS     │                     │
    │                     │                     │                     │
    │                     │  9. Vérif RPPS ────────────────────────>  │
    │                     │  10. active: true  <────────────────────  │
    │                     │                     │                     │
    │  11. Session créée  │                     │                     │
    │<────────────────────│                     │                     │

Paramètres de la requête /authorize

Paramètre Valeur Rôle
response_type code Authorization Code Flow
scope openid scope_all Tous les claims professionnels
state Random, 32 chars minimum Protection anti-CSRF
nonce Random, 32 chars minimum Protection anti-replay
acr_values eidas1 Valeur requise par PSC

Un point qui surprend souvent les développeurs venant de FranceConnect : le paramètre acr_values doit valoir eidas1, pas eidas2. Le niveau d'assurance eIDAS Substantial est garanti par le moyen d'authentification utilisé (CPS ou e-CPS), pas par la valeur de ce paramètre. Pour vérifier le niveau effectif a posteriori, consultez le claim auth_level dans la réponse : "1" correspond à eIDAS Low, "2" à eIDAS Substantial.


Endpoints PSC : sandbox et production

PSC est hébergé sur une infrastructure Keycloak, ce qui explique le pattern d'URLs /auth/realms/esante-wallet/. L'ANS met à disposition deux environnements : le BAS (Bac À Sable) pour l'intégration et la production.

Environnement BAS (sandbox)

Endpoint URL
Discovery https://auth.bas.psc.esante.gouv.fr/auth/realms/esante-wallet/.well-known/openid-configuration
Authorize https://wallet.bas.psc.esante.gouv.fr/auth
Token https://auth.bas.psc.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/token
UserInfo https://auth.bas.psc.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/userinfo
Logout https://auth.bas.psc.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/logout

Environnement Production

Endpoint URL
Discovery https://auth.esw.esante.gouv.fr/auth/realms/esante-wallet/.well-known/openid-configuration
Authorize https://wallet.esw.esante.gouv.fr/auth
Token https://auth.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/token
UserInfo https://auth.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/userinfo
Logout https://auth.esw.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/logout

Vous l'aurez remarqué : l'endpoint Authorize utilise un host différent (wallet.*) des autres endpoints (auth.*). C'est une source d'erreurs fréquente. Si vous copiez-collez les URLs en modifiant juste le path, votre flow d'authentification échouera silencieusement.

Autre subtilité : le sous-domaine sandbox est bas.psc et non bas.esw. On trouve encore des documentations tierces qui utilisent bas.esw, ce qui ne fonctionne pas.


Décoder les claims PSC : RPPS, SubjectRole et SubjectNameID

L'appel au endpoint /userinfo retourne un ensemble de claims spécifiques au secteur santé. Avec le scope openid scope_all, voici la structure de la réponse :

{
  "sub": "f{RPPS_NUMBER}",
  "given_name": "Marie",
  "family_name": "MARTIN",
  "SubjectNameID": "8{RPPS_NUMBER}",
  "preferred_username": "8{RPPS_NUMBER}",
  "SubjectOrganization": "Cabinet Dr MARTIN",
  "SubjectOrganizationID": "1{FINESS_NUMBER}",
  "SubjectRole": [
    "10^1.2.250.1.213.1.1.5.5"
  ],
  "PSI_Locale": "1.2.250.1.71.4.2.1",
  "otherIds": [
    {
      "identifiant": "{RPPS_NUMBER}",
      "origine": "RPPS",
      "qualite": 1
    }
  ],
  "SubjectRefPro": {
    "codeCivilite": "MME",
    "exercices": [
      {
        "codeProfession": "10",
        "codeCategorieProfessionnelle": "C",
        "codeSavoirFaire": "SM26",
        "activities": [...]
      }
    ]
  }
}

Le SubjectNameID : extraire le numéro RPPS

Le SubjectNameID suit le format {type_digit}{identifiant}. Le premier chiffre indique le type d'identifiant :

Préfixe Signification
8 Numéro RPPS
3 Numéro ADELI
9 Étudiant
0 Identifiant national (non significatif)

Pour une application de téléconsultation, vous attendez un SubjectNameID commençant par 8. Les chiffres restants constituent le numéro RPPS du professionnel.

Attention : n'utilisez pas le claim sub comme identifiant RPPS. En 2026, PSC évolue vers Pro Santé Identité (PSI) : le sub devient un identifiant technique non-métier. Un nouveau champ PSISubjectNameID sera introduit pour l'identifiant professionnel. Anticipez cette migration dès maintenant en vous appuyant sur SubjectNameID et non sur sub.

Le SubjectRole : vérifier la profession

Le claim SubjectRole est un tableau de chaînes au format code^OID (deux champs séparés par ^).

Code Profession
10 Médecin
21 Pharmacien
40 Chirurgien-dentiste
60 Infirmier
70 Masseur-kinésithérapeute

PSC authentifie tous les professionnels de santé. Si votre application est réservée aux médecins, vous devez vérifier que le premier élément du split sur ^ vaut 10.

Les autres scopes disponibles

Le scope scope_all est un raccourci qui retourne l'ensemble des claims, mais PSC propose aussi des scopes granulaires :

Scope Description
openid Obligatoire, retourne le sub
scope_all Tous les claims professionnels
profile Identité de base (nom, prénom)
rpps Identifiants RPPS
interop Claims d'interopérabilité
referentiel Données du référentiel professionnel

Pour la plupart des cas d'usage, openid scope_all est le choix le plus simple.


Implémentation NestJS pas à pas

Passons au code. L'intégration dans un backend NestJS repose sur Passport avec une strategy OIDC.

1. La strategy Passport

// auth/strategies/psc.strategy.ts
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-openidconnect';

@Injectable()
export class ProSanteConnectStrategy extends PassportStrategy(Strategy, 'psc') {
  constructor(private configService: ConfigService) {
    super({
      issuer: configService.get('PSC_ISSUER'),
      authorizationURL: configService.get('PSC_AUTHORIZATION_URL'),
      tokenURL: configService.get('PSC_TOKEN_URL'),
      userInfoURL: configService.get('PSC_USERINFO_URL'),
      clientID: configService.get('PSC_CLIENT_ID'),
      clientSecret: configService.get('PSC_CLIENT_SECRET'),
      callbackURL: configService.get('PSC_CALLBACK_URL'),
      scope: 'openid scope_all',
      // acr_values=eidas1 requis par PSC
      customParams: { acr_values: 'eidas1' },
    });
  }

  async validate(accessToken: string, refreshToken: string, profile: any) {
    const rppsNumber = this.extractRpps(profile.SubjectNameID);

    if (!rppsNumber) {
      throw new UnauthorizedException(
        'RPPS number not found in PSC response',
      );
    }

    // Vérifier que c'est bien un médecin (code 10)
    const professionCode = this.extractProfessionCode(profile.SubjectRole);
    if (professionCode !== '10') {
      throw new UnauthorizedException(
        'Only doctors (code 10) are authorized',
      );
    }

    return {
      rppsNumber,
      firstName: profile.given_name,
      lastName: profile.family_name,
      professionCode,
      organization: profile.SubjectOrganization,
    };
  }

  private extractRpps(subjectNameId: string): string | null {
    if (subjectNameId?.startsWith('8')) {
      return subjectNameId.substring(1);
    }
    return null;
  }

  private extractProfessionCode(subjectRole: string[]): string {
    // Format: "code^OID" — ex: "10^1.2.250.1.213.1.1.5.5"
    const role = subjectRole?.[0];
    if (role) {
      return role.split('^')[0] || 'unknown';
    }
    return 'unknown';
  }
}

2. Les variables d'environnement

# Pro Santé Connect — Sandbox (BAS)
PSC_ISSUER=https://auth.bas.psc.esante.gouv.fr/auth/realms/esante-wallet
PSC_AUTHORIZATION_URL=https://wallet.bas.psc.esante.gouv.fr/auth
PSC_TOKEN_URL=https://auth.bas.psc.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/token
PSC_USERINFO_URL=https://auth.bas.psc.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/userinfo
PSC_LOGOUT_URL=https://auth.bas.psc.esante.gouv.fr/auth/realms/esante-wallet/protocol/openid-connect/logout
PSC_CLIENT_ID=your-psc-client-id
PSC_CLIENT_SECRET=your-psc-client-secret
PSC_CALLBACK_URL=https://your-app.example.com/auth/psc/callback

# Annuaire Santé (vérification RPPS)
ANNUAIRE_SANTE_URL=https://gateway.api.esante.gouv.fr
ANNUAIRE_SANTE_API_KEY=your-gravitee-api-key

Notez que PSC_AUTHORIZATION_URL pointe vers wallet.bas.psc tandis que les autres endpoints utilisent auth.bas.psc. Cette différence est volontaire et doit être respectée.


Vérifier le RPPS via l'API Annuaire Santé (FHIR R4)

L'authentification PSC confirme l'identité du professionnel, mais ne garantit pas qu'il est toujours en exercice. Un médecin suspendu ou radié conserve ses identifiants PSC un certain temps. La vérification contre l'Annuaire Santé est donc indispensable.

Le service de vérification

L'ANS expose une API FHIR R4 sur le endpoint gateway.api.esante.gouv.fr :

// auth/services/rpps-verification.service.ts
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class RppsVerificationService {
  constructor(
    private httpService: HttpService,
    private configService: ConfigService,
  ) {}

  async verify(rppsNumber: string): Promise<boolean> {
    const url = `${this.configService.get('ANNUAIRE_SANTE_URL')}/fhir/v1/Practitioner`;

    const response = await this.httpService.axiosRef.get(url, {
      params: {
        identifier: `http://rpps.fr|${rppsNumber}`,
      },
      headers: {
        'GRAVITEE-API-KEY': this.configService.get('ANNUAIRE_SANTE_API_KEY'),
      },
    });

    const bundle = response.data;
    if (!bundle.entry?.length) {
      return false;
    }

    const practitioner = bundle.entry[0].resource;
    return practitioner.active === true;
  }
}

Points de vérification

L'appel FHIR retourne un Bundle contenant la ressource Practitioner. Quatre vérifications sont nécessaires :

  1. Le praticien existe dans l'annuaire (le bundle contient au moins une entrée)
  2. Le champ active vaut true (le médecin est en exercice)
  3. La qualification correspond à un médecin (cross-check avec le SubjectRole de PSC)
  4. Les nom et prénom correspondent aux données PSC (cohérence)

Pour éviter de surcharger l'API Annuaire, mettez en cache le résultat de vérification pendant 24 heures maximum. Le statut d'un praticien ne change pas d'une minute à l'autre, mais vérifier à chaque connexion reste la bonne pratique.

L'obtention de la clé API se fait via le portail openfhir.annuaire.sante.fr. Nous détaillerons l'intégration complète de cette API dans un article dédié.


Les 7 pièges qui font perdre des semaines aux développeurs

Après plusieurs intégrations PSC, voici les erreurs les plus fréquentes que nous avons rencontrées (ou évitées de justesse).

1. Confondre les sous-domaines sandbox. L'URL sandbox utilise bas.psc et non bas.esw. Certaines documentations tierces indiquent auth.bas.esw.esante.gouv.fr, ce qui retourne une erreur DNS. Le bon domaine est auth.bas.psc.esante.gouv.fr.

2. Mettre acr_values=eidas2 au lieu de eidas1. L'intuition dit "Substantial = eidas2", mais PSC attend eidas1. Le niveau Substantial est garanti par le moyen d'authentification (CPS/e-CPS), pas par ce paramètre.

3. Utiliser le sub comme identifiant RPPS. Le numéro RPPS se trouve dans SubjectNameID (préfixé par 8), pas dans sub. Avec l'évolution PSI 2026, le sub deviendra un identifiant purement technique.

4. Oublier de vérifier la profession dans SubjectRole. PSC authentifie tous les professionnels de santé : médecins, pharmaciens, infirmiers, kinés. Si votre app est réservée aux médecins, vérifiez que le code profession est 10. Le format est code^OID (deux champs, pas trois).

5. Ne pas vérifier le RPPS contre l'Annuaire Santé. PSC confirme l'identité mais pas le statut d'exercice. Un médecin radié peut encore s'authentifier via PSC. La vérification FHIR est le filet de sécurité.

6. Sous-estimer le délai d'habilitation Datapass. Le processus administratif auprès de l'ANS prend plusieurs semaines (instruction, validation, passage en production). Lancez la demande dès le début du projet pour que les délais courent en parallèle du développement.

7. Ignorer les évolutions PSI 2026. PSC migre vers Pro Santé Identité. Le champ sub va changer de nature, et un nouveau PSISubjectNameID apparaîtra. Si vous construisez votre modèle de données autour de sub, vous devrez migrer.


Évolutions 2026 : Pro Santé Identité (PSI)

L'ANS fait évoluer PSC vers Pro Santé Identité (PSI) au cours de l'année 2026. Deux changements majeurs sont à anticiper.

Le champ sub devient un identifiant technique non-métier. Il ne contiendra plus de référence au numéro RPPS. Pour les applications qui utilisent actuellement sub comme clé primaire en base de données, une migration sera nécessaire.

Un nouveau champ PSISubjectNameID est introduit pour porter l'identifiant professionnel. C'est ce champ qui remplacera le rôle actuel de SubjectNameID.

Si vous démarrez un nouveau projet, structurez votre modèle de données autour de SubjectNameID (et demain PSISubjectNameID) plutôt que sub. Pour un projet existant, prévoyez une colonne supplémentaire et un script de migration. L'évolution est déjà disponible en BAS (sandbox) depuis mars 2026 et sera déployée en production dans les mois à venir.


Le processus d'habilitation Datapass

Avant de toucher au code, vous devez obtenir vos credentials auprès de l'ANS. Le processus passe par Datapass, la plateforme interministérielle de gestion des habilitations API.

Les 8 étapes du raccordement PSC

Étape Durée estimée Action
1. Inscription Datapass 1 jour Créer un compte sur datapass.api.gouv.fr
2. Dossier d'habilitation 3-5 jours Remplir le formulaire PSC, justifier le besoin
3. Instruction ANS ~2 semaines Validation technique et réglementaire
4. Credentials BAS 1-2 jours Réception du client_id + client_secret sandbox
5. Développement + tests 2-3 semaines Intégration technique en sandbox
6. Demande production 1 jour Via Datapass, une fois les tests validés
7. Validation production ~2 semaines Revue finale par l'ANS
8. Credentials PROD 1-2 jours Réception du client_id + client_secret production

Documents à préparer

Le dossier Datapass exige :

  • La description du service : finalité, public cible, fonctionnalités
  • La justification du besoin PSC : pourquoi l'identification des professionnels est nécessaire
  • L'architecture technique : schéma montrant comment PSC s'intègre dans votre application
  • La politique de sécurité : mesures de protection des données de santé
  • La preuve d'hébergement certifié HDS : vos données de santé doivent être chez un hébergeur certifié
  • Les coordonnées du DPO (Délégué à la Protection des Données)
  • Les URLs : callback, logout, CGU du service

Le conseil le plus important : lancez le Datapass dès le kick-off du projet. Les semaines de délai administratif courent en parallèle du développement. Si vous attendez la fin du code pour démarrer l'habilitation, vous ajoutez plusieurs semaines au planning pour rien.


FAQ : les questions les plus fréquentes sur Pro Santé Connect

Pro Santé Connect est-il obligatoire ?

Oui, depuis le 1er janvier 2023. L'arrêté du 4 avril 2022 impose PSC pour les services numériques en santé nationaux et territoriaux. Les services locaux fortement intégrés au système de santé sont également concernés.

Quelle différence entre FranceConnect et Pro Santé Connect ?

FranceConnect authentifie les citoyens (patients) avec un niveau eIDAS Low. PSC authentifie les professionnels de santé (médecins, pharmaciens, infirmiers) avec un niveau eIDAS Substantial grâce à la CPS ou l'e-CPS. Les deux utilisent le protocole OpenID Connect, mais les claims retournés sont différents : PSC fournit le numéro RPPS, le rôle professionnel et l'organisation.

Comment obtenir un accès à la sandbox PSC ?

En déposant une demande d'habilitation sur datapass.api.gouv.fr. Après instruction par l'ANS (environ 2 semaines), vous recevez un client_id et un client_secret pour l'environnement BAS.

L'e-CPS fonctionne-t-elle avec Pro Santé Connect ?

Oui. Les deux moyens d'authentification (carte CPS physique et application mobile e-CPS) sont gérés de manière transparente côté PSC. Votre application n'a pas à les distinguer : PSC présente le choix au médecin et les claims retournés sont identiques dans les deux cas. Avec plus de 320 000 utilisateurs actifs, l'e-CPS est le moyen privilégié pour la téléconsultation car elle ne nécessite pas de lecteur de carte.

Combien de temps prend l'habilitation PSC ?

Comptez plusieurs semaines au total : instruction ANS, développement en sandbox, puis validation pour la production. Le délai administratif est le facteur limitant, d'où l'importance de lancer la demande Datapass le plus tôt possible dans le projet.

Faut-il un hébergement HDS pour utiliser PSC ?

Le dossier Datapass demande une preuve d'hébergement certifié HDS (Hébergeur de Données de Santé). Si votre application manipule des données de santé à caractère personnel, l'hébergement HDS est de toute façon une obligation légale indépendante de PSC. La certification HDS v2 est en vigueur depuis novembre 2024, et après le 16 mai 2026, seuls les hébergeurs certifiés HDS v2 pourront légalement héberger des données de santé pour le compte de tiers.


Conclusion

L'intégration de Pro Santé Connect est techniquement accessible pour toute équipe familière avec OpenID Connect. Le protocole est standard, le code se résume à une Passport strategy et un service de vérification RPPS.

Le vrai sujet n'est pas le développement, c'est la préparation : lancer le Datapass tôt, connaître les bons endpoints (et surtout le host séparé pour Authorize), parser correctement les claims santé, et anticiper les évolutions PSI 2026.

Vous développez une application e-santé et vous avez besoin d'intégrer Pro Santé Connect ? Chez Bob le développeur, on accompagne les startups et établissements de santé depuis 2017. Parlons de votre projet.

Prêt à vous lancer ?

La newsletter qu'on n'ignore pas

Abonnez-vous à notre newsletter pour recevoir nos derniers articles, retours d'expérience et conseils tech directement dans votre boîte mail.

Désinscription en un clic. Vos données restent privées.