feat(auth): init Authlib + provider LinkedIn (config env) (#88)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,12 @@ USERS_DB_PATH=./users.sqlite
|
|||||||
SECRET_KEY= # à générer : python -c "import secrets; print(secrets.token_hex(32))"
|
SECRET_KEY= # à générer : python -c "import secrets; print(secrets.token_hex(32))"
|
||||||
APP_BASE_URL=http://localhost:8050
|
APP_BASE_URL=http://localhost:8050
|
||||||
|
|
||||||
|
# Connexion LinkedIn (OpenID Connect) — créer une app sur le LinkedIn Developer Portal,
|
||||||
|
# activer "Sign In with LinkedIn using OpenID Connect", déclarer le redirect URI
|
||||||
|
# {APP_BASE_URL}/auth/linkedin/callback
|
||||||
|
LINKEDIN_CLIENT_ID=
|
||||||
|
LINKEDIN_CLIENT_SECRET=
|
||||||
|
|
||||||
# Brevo — envoi des emails transactionnels (vérification email, reset mot de passe)
|
# Brevo — envoi des emails transactionnels (vérification email, reset mot de passe)
|
||||||
BREVO_API_KEY= # clé API transactionnelle Brevo
|
BREVO_API_KEY= # clé API transactionnelle Brevo
|
||||||
BREVO_TEMPLATE_VERIFY_ID= # ID numérique du template "vérification d'adresse"
|
BREVO_TEMPLATE_VERIFY_ID= # ID numérique du template "vérification d'adresse"
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ dependencies = [
|
|||||||
"brevo-python==5.0.0rc1",
|
"brevo-python==5.0.0rc1",
|
||||||
"flask-wtf",
|
"flask-wtf",
|
||||||
"email-validator",
|
"email-validator",
|
||||||
|
"authlib",
|
||||||
"flask-cors>=6.0.2",
|
"flask-cors>=6.0.2",
|
||||||
"flask-smorest>=0.46.0",
|
"flask-smorest>=0.46.0",
|
||||||
"marshmallow>=3.20.0",
|
"marshmallow>=3.20.0",
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from authlib.integrations.flask_client import OAuth
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
LINKEDIN_DISCOVERY_URL = (
|
||||||
|
"https://www.linkedin.com/oauth/.well-known/openid-configuration"
|
||||||
|
)
|
||||||
|
|
||||||
|
oauth = OAuth()
|
||||||
|
|
||||||
|
|
||||||
|
def init_oauth(app: Flask) -> None:
|
||||||
|
oauth.init_app(app)
|
||||||
|
oauth.register(
|
||||||
|
name="linkedin",
|
||||||
|
client_id=os.getenv("LINKEDIN_CLIENT_ID"),
|
||||||
|
client_secret=os.getenv("LINKEDIN_CLIENT_SECRET"),
|
||||||
|
server_metadata_url=LINKEDIN_DISCOVERY_URL,
|
||||||
|
client_kwargs={"scope": "openid profile email"},
|
||||||
|
)
|
||||||
@@ -6,6 +6,7 @@ from flask_wtf.csrf import CSRFProtect
|
|||||||
|
|
||||||
from src.auth import db, mailer
|
from src.auth import db, mailer
|
||||||
from src.auth.models import load_user
|
from src.auth.models import load_user
|
||||||
|
from src.auth.oauth import init_oauth
|
||||||
from src.utils import DEVELOPMENT, logger
|
from src.utils import DEVELOPMENT, logger
|
||||||
|
|
||||||
_csrf: CSRFProtect | None = None
|
_csrf: CSRFProtect | None = None
|
||||||
@@ -47,6 +48,8 @@ def init_auth(app: Flask) -> None:
|
|||||||
|
|
||||||
app.register_blueprint(auth_bp)
|
app.register_blueprint(auth_bp)
|
||||||
|
|
||||||
|
init_oauth(app)
|
||||||
|
|
||||||
_csrf = CSRFProtect(app)
|
_csrf = CSRFProtect(app)
|
||||||
|
|
||||||
if not os.getenv("BREVO_API_KEY"):
|
if not os.getenv("BREVO_API_KEY"):
|
||||||
@@ -54,3 +57,9 @@ def init_auth(app: Flask) -> None:
|
|||||||
"BREVO_API_KEY non défini : les emails d'auth échoueront. "
|
"BREVO_API_KEY non défini : les emails d'auth échoueront. "
|
||||||
"Définissez les variables BREVO_* dans .env pour envoyer des emails."
|
"Définissez les variables BREVO_* dans .env pour envoyer des emails."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not os.getenv("LINKEDIN_CLIENT_ID"):
|
||||||
|
logger.warning(
|
||||||
|
"LINKEDIN_CLIENT_ID non défini : la connexion LinkedIn échouera. "
|
||||||
|
"Définissez LINKEDIN_CLIENT_ID / LINKEDIN_CLIENT_SECRET dans .env."
|
||||||
|
)
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ def app(users_db_path, monkeypatch):
|
|||||||
from src.auth.setup import init_auth
|
from src.auth.setup import init_auth
|
||||||
|
|
||||||
monkeypatch.setenv("SECRET_KEY", "test-secret-key")
|
monkeypatch.setenv("SECRET_KEY", "test-secret-key")
|
||||||
|
monkeypatch.setenv("LINKEDIN_CLIENT_ID", "test-client-id")
|
||||||
|
monkeypatch.setenv("LINKEDIN_CLIENT_SECRET", "test-client-secret")
|
||||||
|
monkeypatch.setenv("APP_BASE_URL", "http://localhost:8050")
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config["WTF_CSRF_ENABLED"] = False
|
app.config["WTF_CSRF_ENABLED"] = False
|
||||||
init_auth(app)
|
init_auth(app)
|
||||||
|
|||||||
Reference in New Issue
Block a user