Salut à tous, aujourd’hui on regarde comment déployer Authentik devant son Nginx Proxy Manager. Si vous vous rappelez j’ai plusieurs services web derrière mon reverse proxy NPM (et presque autant de façons de me connecter à chacun d’eux). Une Basic Auth par-ci, un compte local par-là, puis un autre mot de passe dans l’application elle-même. Cela fonctionnait, mais la collection de creds commençait sérieusement à ressembler à un élevage industriel (avez vous entendus parler de bitwarden notre sauveur?).
Bref, je voulais donc mettre en place un SSO : une seule identité, une authentification forte avec mes YubiKeys ou une passkey, puis des droits différents selon l’application. Comme tout passait déjà par mon reverse proxy, le projet s’est assez naturellement transformé en déploiement d’Authentik avec Nginx Proxy Manager.
Le but n’était pas de remplacer NPM. Il sait déjà très bien publier les services, gérer les certificats TLS et envoyer chaque requête au bon conteneur. Authentik devait seulement lui apporter ce qui lui manquait : savoir qui se présente et décider s’il a le droit de passer.
Bienvenue dans la treizième partie de ma série Docker et Portainer. Celle où l’on remplace enfin les petites fenêtres grises de la Basic Auth par une vraie porte d’entrée commune (compatible avec l’autofill du password manager \o/). Avec des YubiKey, formidables jusqu’au jour où elles décide de visiter l’estomac du chien, et donc des passkey aussi.
Rappel des articles de la série « Docker et Portainer »
- Les conteneurs pour les débutants
- Créer une stack vsftpd mono-image
- Déployer une stack Docker Guacamole
- Docker, OpenVPN et Splunk
- Customiser un conteneur PHP-FPM
- Déployer Nextcloud avec Docker
- Mettre à jour Portainer et ses conteneurs
- Déployer Jitsi Meet avec Docker
- Superviser Docker avec Splunk
- Installer TheHive et Cortex avec Docker
- Installer OpenCTI avec Docker
- MariaDB, quand latest casse les sauvegardes
- Authentik avec Nginx Proxy Manager et des passkeys
Pourquoi remplacer la Basic Auth ?
La Basic Auth HTTP n’est pas inutile. Derrière HTTPS, elle constitue une barrière simple devant une interface qui ne propose pas de système d’authentification. J’en ai utilisé pendant des années et elles ont parfaitement rempli ce rôle.
Mais la Basic Auth HTTP ne sait faire que cela. Le navigateur renvoie le même identifiant et le même mot de passe à chaque requête. Il n’y a ni vraie session centralisée, ni second facteur, ni enrôlement de passkey, ni gestion agréable des utilisateurs. Et si une personne doit perdre l’accès à trois services, il faut penser à modifier trois configurations.
Authentik déplace cette décision dans un fournisseur d’identité commun. Je peux y créer mes utilisateurs et mes groupes, imposer une YubiKey, donner accès à une application sans ouvrir les autres, puis révoquer le tout au même endroit. Une fois connecté, la session Authentik peut aussi être réutilisée par les autres services autorisés. Voilà le SSO dans sa version utile, pas simplement un nouveau formulaire plus joli.
Il reste évidemment un point à ne pas oublier : centraliser l’identité centralise aussi une panne potentielle. Vous devez donc pensez à vos accès de secours : accès SSH indépendant, comptes administrateurs locaux, codes de récupération et plusieurs clés physiques.
Pourquoi Authentik ?
Je cherchais une solution autohébergée, gratuite, déployable dans Portainer, compatible avec les passkeys et capable de s’intégrer aussi bien à une application moderne qu’à une vieille interface web qui n’a jamais entendu parler d’OpenID Connect.
Authentik cochait ces cases sans m’imposer de remplacer Nginx Proxy Manager. Il propose des utilisateurs, des groupes, des flows d’authentification, WebAuthn/FIDO2, plusieurs types de providers et un outpost embarqué capable de répondre aux demandes d’authentification du reverse proxy. L’interface demande un petit temps d’adaptation, notamment parce qu’une « application » et son « provider » sont deux objets liés, mais la logique finit par devenir assez claire.
Internet
|
v
Nginx Proxy Manager - HTTPS, certificat et routage
|
+---- demande à Authentik : cet utilisateur peut-il passer ?
| |
| passkey / YubiKey
| |
+---- oui --------------------------+
|
v
Application protégéeLa stack elle-même reste classique : un serveur Authentik, un worker et PostgreSQL avec des volumes persistants. Seul le serveur doit être joignable par NPM sur un réseau Docker commun. Aucun port Authentik ou PostgreSQL n’a besoin d’être publié directement sur l’hôte.
J’ai chargé les secrets comme variables protégées dans Portainer et épinglé une version précise plutôt que d’utiliser latest. Une nouvelle branche d’Authentik est d’ailleurs sortie quelques jours après mon installation, excellente démonstration involontaire du principe. La documentation Docker Compose officielle d’Authentik reste le bon point de départ, avec une lecture des notes de version avant chaque mise à jour.
OIDC, OAuth2, SAML ou Forward Auth : qui fait quoi ?
C’est le point qui m’avait le plus embrouillé au début, alors qu’il tient finalement en une question : l’application sait-elle parler directement à un fournisseur d’identité ?
OIDC et OAuth2 : l’application participe au SSO
OpenID Connect s’appuie sur OAuth2 et lui ajoute une couche d’identité. En pratique, l’application redirige le navigateur vers Authentik, récupère un code, l’échange contre un jeton, puis crée sa propre session pour l’utilisateur. Elle connaît donc son identité et peut lui attribuer un rôle.

C’est le mécanisme que j’ai retenu pour Guacamole, grâce à son extension OpenID, et pour Portainer avec son authentification OAuth. Dans les deux cas, le bouton SSO remplace réellement la saisie du mot de passe applicatif pendant le parcours normal.
SAML : la même idée, avec davantage de XML
SAML répond au même besoin général d’échange d’identité entre une application et un fournisseur. Il est juste… plus vieux ! (Oui je sais, comme moi). On le rencontre encore beaucoup dans les logiciels d’entreprise. S’il s’agit du protocole nativement supporté par votre application (genre Splunk), Authentik sait jouer le rôle de fournisseur d’identité. Je ne vais pas dérouler ici une configuration SAML complète : les URLs, certificats et attributs attendus dépendent beaucoup trop du logiciel concerné.
Forward Auth : NPM pose la question à la porte
Le Forward Auth fonctionne autrement. L’application n’échange aucun jeton avec Authentik. Pour chaque requête, Nginx Proxy Manager effectue un petit sous-appel vers l’outpost Authentik. Si la réponse est positive, il laisse passer la requête vers le service. Sinon, il redirige le navigateur vers le flow de connexion.
C’est beaucoup plus générique. Une interface web sans OAuth, sans OIDC et sans SAML peut ainsi profiter d’une protection centralisée et de passkeys sans être modifiée.
En revanche, Authentik ne crée pas magiquement une session dans l’application. Si celle-ci possède son propre formulaire de connexion et ne sait pas exploiter une identité transmise par le proxy, elle le présentera encore après le passage par Authentik. Le Forward Auth remplace alors la Basic Auth située devant le service, mais pas son authentification native.
Guacamole m’a justement permis de voir la différence. Je l’ai d’abord protégé avec Forward Auth : la barrière Authentik fonctionnait, mais Guacamole demandait encore son compte local. Une fois le principe validé, j’e suis passé à j’ai utilisé son extension OpenID pour obtenir un vrai SSO applicatif. Ce n’était pas un échec, c’était simplement deux niveaux d’intégration différents.
La règle est très simple : utilisez OIDC/OAuth2, ou à défaut SAML quand l’application le supporte l’un des 2. Et gardez Forward Auth pour les autres, ou comme première barrière pendant une migration.
Les passkeys, et le piège du nouvel utilisateur
Le gros intérêt d’Authentik par rapport à mes anciennes Basic Auth se trouve ici. WebAuthn permet d’utiliser une clé FIDO2 comme une YubiKey, mais aussi Windows Hello, Touch ID ou une passkey conservée par un système ou un gestionnaire compatible. Le serveur ne reçoit plus un secret réutilisable de la même manière qu’avec un mot de passe HTTP.
J’ai enrôlé mes deux trois YubiKeys et généré des codes de récupération stockés hors ligne. Une clé reste avec moi, l’autre à la maison, la troisième au taf. Cela paraît un peu maniaque jusqu’au jour où la clé principale casse, disparaît ou part faire un tour dans le lave-linge.
J’ai tout de même rencontré un vrai piège lors de l’arrivée d’un second utilisateur. Mon étape de validation MFA acceptait bien WebAuthn, mais son action pour une personne sans appareil était réglée sur Deny. Le nouvel utilisateur arrivait donc devant la porte avec son mot de passe, puis se faisait refuser parce qu’il n’avait pas encore de clé… sans qu’on lui propose de l’enrôler.
La correction consiste à choisir Configure dans « Not configured action » et à associer une étape d’enrôlement WebAuthn. Authentik injecte alors cette étape dans le flow au premier login, puis poursuit uniquement lorsque l’enrôlement a réussi. C’est exactement le comportement décrit dans la documentation de l’Authenticator Validation stage (RTFM quoi).
C’est le seul incident de déploiement que j’ai eu et vous conseille vraiment de retenir : testez le parcours d’un utilisateur tout frais. Un administrateur qui possède déjà deux clés ne voit jamais le problème.
How-to : remplacer une Basic Auth NPM par Authentik
Le scénario suivant ne dépend pas de mes applications. Il part d’un proxy host Nginx Proxy Manager déjà fonctionnel et remplace uniquement son Access List en Basic Auth par un Forward Auth Authentik. L’application peut être n’importe quel service web, tant que vous vérifiez ses WebSockets, ses appels API et son éventuel login natif.
1. Préparer Authentik et un chemin de retour
Déployez Authentik selon sa documentation, avec des volumes persistants, des secrets hors du Compose et une version validée. Publiez ensuite son propre nom HTTPS dans NPM, par exemple auth.example.org, vers le port interne 9000 du serveur Authentik.
Ce proxy host doit être joignable sans Basic Auth ni Forward Auth. Oui, NPM l’affiche donc comme « Publicly Accessible ». La page d’Authentik doit être accessible pour pouvoir authentifier les autres pages, hein. Ce sont ses flows qui contrôlent ensuite l’accès.
Avant de modifier le service pilote, exportez ou copiez sa configuration NPM actuelle : upstream, certificat, Access List et contenu du champ Advanced. Gardez aussi une session d’administration ouverte et un accès indépendant au serveur. Le rollback consistera simplement à restaurer cette configuration.
2. Créer une application et son Proxy Provider
Dans Authentik, créez une application puis un provider de type Proxy. Choisissez le mode Forward auth (single application) et indiquez comme External host l’URL publique exacte du service, par exemple https://app.example.org.
Le mode single application demande un provider par service, mais c’est volontaire. Il permet d’attacher des groupes et des règles différents à chaque application. Le mode domain-level évite de créer plusieurs providers, mais ne permet pas la même séparation fine. Protéger tout un domaine d’un seul coup est rarement la bonne première expérience.
Associez ensuite l’application au provider, ajoutez-la à l’outpost embarqué, puis créez un binding vers le groupe autorisé. Testez aussi un compte qui ne fait pas partie du groupe. Une redirection réussie ne prouve pas encore que les autorisations sont correctes.
3. Ajouter le sous-appel Authentik dans NPM
Le template Nginx évolue avec Authentik. Prenez donc la version correspondant à votre installation dans la documentation officielle pour Nginx Proxy Manager. Remplacez authentik-server par le nom ou l’adresse privée réellement joignable depuis NPM. Ne publiez pas pour autant le port 9000 sur Internet. Le serveur Authentik et NPM doivent simplement partager un réseau Docker ou disposer d’un autre chemin interne contrôlé. Vous devez déployer cette configuration dans la petite roue « Advanced » de NPM :

Le cœur du mécanisme ressemble à ceci :
proxy_buffers 8 16k;
proxy_buffer_size 32k;
port_in_redirect off;
set $ak_http_host $http_host;
if ($ak_http_host = "") {
set $ak_http_host $host;
}
location / {
proxy_pass $forward_scheme://$server:$port;
include conf.d/include/proxy.conf;
auth_request /outpost.goauthentik.io/auth/nginx;
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
}
location /outpost.goauthentik.io {
proxy_pass http://authentik-server:9000/outpost.goauthentik.io;
proxy_set_header Host $ak_http_host;
proxy_set_header X-Original-URI "";
proxy_set_header X-Original-URL $scheme://$ak_http_host$request_uri;
proxy_set_header Authorization "";
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
location @goauthentik_proxy_signin {
internal;
add_header Set-Cookie $auth_cookie;
return 302 /outpost.goauthentik.io/start?rd=$scheme://$ak_http_host$request_uri;
}Ce bloc est volontairement limité au contrôle d’accès. Si votre application utilise des WebSockets, une API avec un header Authorization ou des en-têtes particuliers, repartez du template officiel complet et adaptez la configuration. Ne transmettez jamais aveuglément au backend un header d’identité fourni par le navigateur.
4. Garder les deux barrières pendant le test
Lors de la mise en place, conservez temporairement l’Access List Basic Auth. Vous devez alors franchir la Basic Auth, puis Authentik, puis éventuellement le login natif de l’application. Ce n’est pas élégant, mais cela permet de tester le nouveau contrôle sans exposer votre app en cas de problème.
5. Retirer uniquement la Basic Auth
Une fois les tests terminés, passez l’Access List du proxy host à « Publicly Accessible », mais ne supprimez pas la configuration Advanced. Dans ce contexte, ce libellé signifie seulement que NPM n’ajoute plus sa Basic Auth. Le sous-appel Authentik continue de filtrer chaque requête.
Enfin, migrez une application à la fois. Un service qui affiche trois pages HTML et un terminal web en WebSocket n’exerce pas du tout le reverse proxy de la même façon.
Ce que cette architecture Authentik avec Nginx Proxy Manager change vraiment
Le résultat visible est agréable : je touche ma YubiKey ou authorise la Passkey de mon Bitwarden, et Authentik ouvre ma session et les applications autorisées deviennent accessibles, avec un seul login ! Oui, du SSO en 2026, je sais, vous n’avez qu’un mot : Bravo. Les nouveaux utilisateurs peuvent enrôler leur passkey au premier passage, et un groupe suffit pour leur retirer ensuite un service.
Mais le vrai gain se trouve dans la séparation des rôles. Nginx Proxy Manager continue de gérer le HTTPS et les routes. Authentik centralise l’identité, le MFA et les autorisations. Les applications compatibles utilisent leur protocole natif. Les autres profitent au minimum d’une porte d’entrée commune grâce au Forward Auth.
Tout n’est pas devenu « passwordless » par enchantement. L’administration de NPM conserve par exemple son propre login derrière Authentik, et certaines applications garderont leur authentification locale. Cela me convient : je préfère un SSO bien délimité à une suppression enthousiaste de tous les accès de secours.
Au final, Authentik s’est parfaitement glissé entre NPM et mes services sans demander de reconstruire toute l’infrastructure. C’est exactement ce que j’attendais : une identité commune là où c’est utile, des passkeys à la place des mots de passe répétitifs, et toujours une porte de secours quand la magie du SSO décide de prendre sa pause. Bref, Geekez bien mais loguez-vous qu’une seul fois !


