Authentification SSO et OAuth
Configurez la connexion Google, GitHub, HuggingFace et OIDC générique dans Potato. Restreignez l'accès par domaine de messagerie ou organisation GitHub, et utilisez le SSO avec la connexion locale par mot de passe.
Nouveau dans v2.3.0
Par défaut, Potato utilise une connexion simple par nom d'utilisateur, où les annotateurs saisissent n'importe quel nom d'utilisateur pour se connecter. Cela convient au développement local et aux petits projets, mais les déploiements en production ont besoin d'une véritable authentification pour empêcher les accès non autorisés, confirmer l'identité des annotateurs et répondre aux exigences institutionnelles.
Le SSO se configure à un seul endroit. Définissez authentication.method sur oauth, puis listez un ou plusieurs fournisseurs sous authentication.providers. Chaque fournisseur a son propre bouton sur la page de connexion.
Potato intègre les métadonnées d'endpoints de trois fournisseurs : google, github et huggingface. Tout autre nom de fournisseur est traité comme de l'OIDC générique et nécessite une discovery_url.
Démarrage rapide
Une configuration Google minimale :
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
user_identity_field: "email"
secret_key: ${POTATO_SECRET_KEY}Définissez les secrets dans l'environnement plutôt que dans le fichier :
export GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="your-client-secret"
export POTATO_SECRET_KEY="$(python3 -c 'import secrets; print(secrets.token_hex(32))')"secret_key est une clé de premier niveau et ne fait pas partie du bloc authentication. Définissez-la, ou définissez POTATO_SECRET_KEY. Si aucune des deux n'est présente, Potato génère une clé aléatoire, ce qui signifie que chaque redémarrage invalide toutes les sessions, et il écrit un avertissement dans le journal lorsque OAuth est configuré sans elle.
Potato expose deux routes OAuth. /auth/login/<provider> lance le flux et /auth/callback/<provider> reçoit la réponse. Le callback est l'URL que vous enregistrez auprès du fournisseur, donc pour Google il s'agit de https://your-domain.com/auth/callback/google. Il n'existe pas de clé de configuration redirect_uri ; la route est dérivée du nom du fournisseur.
Créez des identifiants OAuth 2.0 de type "Web application" dans la Google Cloud Console, puis ajoutez https://your-domain.com/auth/callback/google comme URI de redirection autorisée. Pour le développement local, http://localhost:8000/auth/callback/google est accepté.
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
allowed_domain: "umich.edu"allowed_domain prend une seule chaîne de domaine. Seuls les comptes dont l'adresse e-mail appartient à ce domaine peuvent se connecter.
GitHub
Enregistrez une OAuth app dans GitHub Settings > Developer settings > OAuth Apps, avec l'URL de callback définie sur https://your-domain.com/auth/callback/github.
authentication:
method: "oauth"
providers:
github:
client_id: ${GITHUB_CLIENT_ID}
client_secret: ${GITHUB_CLIENT_SECRET}
allowed_org: "my-research-lab"allowed_org prend un seul nom d'organisation. Lorsqu'il est défini, Potato demande automatiquement le scope read:org, vous n'avez donc pas besoin de lister les scopes vous-même. L'annotateur doit être membre public de l'organisation pour que la vérification voie son appartenance.
HuggingFace
Créez une application OAuth sur huggingface.co/settings/applications.
authentication:
method: "oauth"
providers:
huggingface:
client_id: ${HF_CLIENT_ID}
client_secret: ${HF_CLIENT_SECRET}
user_identity_field: "username"Le fournisseur HuggingFace se connecte à l'endpoint de découverte OIDC de HuggingFace et demande openid profile email par défaut.
OIDC générique
Tout nom de fournisseur autre que google, github et huggingface est traité comme de l'OIDC générique et requiert discovery_url. Donnez-lui un display_name pour que le bouton de connexion soit lisible.
authentication:
method: "oauth"
providers:
oidc:
display_name: "University SSO"
discovery_url: "https://sso.university.edu/.well-known/openid-configuration"
client_id: ${OIDC_CLIENT_ID}
client_secret: ${OIDC_CLIENT_SECRET}
scopes:
- "openid"
- "email"
- "profile"L'URL de callback à enregistrer auprès du fournisseur suit la clé du fournisseur, donc un bloc nommé oidc utilise https://your-domain.com/auth/callback/oidc.
URL de découverte des fournisseurs courants :
| Fournisseur | URL de découverte |
|---|---|
| Okta | https://your-org.okta.com/.well-known/openid-configuration |
| Azure AD | https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration |
| Auth0 | https://your-domain.auth0.com/.well-known/openid-configuration |
| Keycloak | https://keycloak.example.com/realms/{realm}/.well-known/openid-configuration |
scopes vaut par défaut ["openid", "email", "profile"].
Plusieurs fournisseurs
providers accepte autant d'entrées que nécessaire, et chacune affiche son propre bouton de connexion.
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
github:
client_id: ${GITHUB_CLIENT_ID}
client_secret: ${GITHUB_CLIENT_SECRET}
oidc:
display_name: "University SSO"
discovery_url: "https://sso.university.edu/.well-known/openid-configuration"
client_id: ${OIDC_CLIENT_ID}
client_secret: ${OIDC_CLIENT_SECRET}Avec user_identity_field: "email", une personne qui se connecte via Google puis, plus tard, via le fournisseur de l'université avec la même adresse est le même utilisateur Potato et retrouve les mêmes attributions.
Identité et inscription automatique
user_identity_field détermine quelle claim du fournisseur devient le nom d'utilisateur Potato. Il accepte email, username, sub ou name, et vaut email par défaut. La valeur compte, car les répertoires de sortie des annotateurs portent le nom de l'utilisateur ; la changer en cours d'étude sépare donc un annotateur de son travail antérieur.
auto_register détermine si une première connexion réussie crée le compte Potato. Il vaut true par défaut.
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
allowed_domain: "umich.edu"
user_identity_field: "email"
auto_register: trueLe contrôle d'accès passe par le fournisseur et non par une liste d'adresses dans la configuration. Pour limiter qui peut se connecter, utilisez allowed_domain pour Google, allowed_org pour GitHub, ou les contrôles de groupes et d'attribution d'applications de votre fournisseur OIDC.
Mode mixte
allow_local_login ajoute le formulaire nom d'utilisateur et mot de passe sous les boutons SSO. Il vaut false par défaut, donc le SSO remplace la connexion locale à moins que vous ne l'activiez.
require_password: true
user_config:
allow_all_users: true
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
allow_local_login: trueUne migration fait fonctionner les deux pendant un temps. Faites passer les annotateurs au fournisseur, puis retirez allow_local_login une fois que tout le monde s'est connecté par ce biais. Le mode mixte couvre aussi les études qui associent des annotateurs de l'institution à des annotateurs externes sans compte dans votre institution.
Les comptes locaux en mode mixte utilisent le même hachage PBKDF2 salé que tout autre compte à mot de passe. Voir Gestion des mots de passe pour les procédures de réinitialisation.
Sessions
La durée de vie des sessions est une clé de premier niveau, exprimée en jours :
session_lifetime_days: 7C'est une secret_key stable qui permet aux sessions de survivre à un redémarrage.
Accès administrateur
Les endpoints d'administration s'authentifient avec une clé d'API plutôt que par le bloc OAuth :
admin_api_key: ${POTATO_ADMIN_API_KEY}Potato lit admin_api_key d'abord dans la configuration, puis dans la variable d'environnement POTATO_ADMIN_API_KEY. Si aucune n'est définie, il génère une clé et l'écrit dans admin_api_key.txt dans le répertoire de la tâche. Les appelants la présentent dans l'en-tête X-API-Key.
HTTPS
Les fournisseurs OAuth exigent des URI de redirection HTTPS en production. localhost en est exempté, donc le développement en HTTP fonctionne sans certificat.
Derrière un reverse proxy, transmettez le schéma d'origine, sinon l'URL de callback construite par Potato utilisera http et le fournisseur la rejettera :
location / {
proxy_pass http://localhost:8000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}Référence de configuration
| Clé | Type | Défaut | Description |
|---|---|---|---|
authentication.method | string | in_memory | in_memory, database, clerk ou oauth |
authentication.providers | dict | requis pour oauth | Une entrée par fournisseur, indexée par le nom du fournisseur |
authentication.user_identity_field | string | email | email, username, sub ou name |
authentication.allow_local_login | bool | false | Affiche le formulaire de mot de passe à côté des boutons SSO |
authentication.auto_register | bool | true | Crée le compte Potato à la première connexion |
secret_key | string | aléatoire | Premier niveau. Une valeur stable est nécessaire pour des sessions persistantes |
session_lifetime_days | int | 7 | Durée des sessions, au premier niveau |
admin_api_key | string | générée | Clé de premier niveau pour les endpoints d'administration |
Clés par fournisseur :
| Clé | Type | Requise | Description |
|---|---|---|---|
client_id | string | oui | Fournie par le fournisseur |
client_secret | string | oui | Fournie par le fournisseur |
discovery_url | string | pour l'OIDC générique | Endpoint de découverte OIDC |
display_name | string | non | Texte du bouton de connexion |
allowed_domain | string | non | Restreint à un domaine de messagerie |
allowed_org | string | non | Restreint à une organisation GitHub |
scopes | list | non | Vaut par défaut ["openid", "email", "profile"] |
Exemple complet
annotation_task_name: "Annotation Project"
task_dir: "."
authentication:
method: "oauth"
providers:
google:
client_id: ${GOOGLE_CLIENT_ID}
client_secret: ${GOOGLE_CLIENT_SECRET}
allowed_domain: "umich.edu"
user_identity_field: "email"
auto_register: true
secret_key: ${POTATO_SECRET_KEY}
session_lifetime_days: 7
admin_api_key: ${POTATO_ADMIN_API_KEY}
data_files:
- "data/instances.jsonl"
item_properties:
id_key: id
text_key: text
annotation_schemes:
- annotation_type: radio
name: sentiment
description: "What is the sentiment of this text?"
labels: [Positive, Neutral, Negative]
output_annotation_dir: "output/"
export_annotation_format: "jsonl"Dépannage
Le fournisseur rejette l'URI de redirection. L'URI enregistrée auprès du fournisseur doit correspondre exactement à /auth/callback/<provider>. Le schéma et tout chemin final font partie de la correspondance, donc un proxy qui ne transmet pas X-Forwarded-Proto produit un callback http que le fournisseur rejette.
Tout le monde est déconnecté après un redémarrage. secret_key n'est pas définie, donc Potato en a généré une nouvelle au démarrage.
Une restriction d'organisation GitHub rejette un membre. Son appartenance à l'organisation est privée. Soit il la rend publique, soit vous retirez allowed_org et contrôlez l'accès autrement.
La validation échoue avec "providers is required". method: "oauth" nécessite au moins une entrée sous providers. La valeur de la méthode est oauth, pas le nom d'un fournisseur.
Pour aller plus loin
- Gestion des mots de passe -- comptes locaux, hachage et procédures de réinitialisation
- Connexion sans mot de passe -- accès par nom d'utilisateur seul pour les tâches ouvertes
- Intégration du crowdsourcing -- authentification sur les plateformes de crowdsourcing
- Tableau de bord d'administration -- gestion des utilisateurs et des permissions
Pour les détails d'implémentation, consultez la documentation source.