From 8a24747656a93faed7080c22137a4ed67e17d286 Mon Sep 17 00:00:00 2001 From: Koman Rudden Date: Thu, 8 Oct 2026 06:35:02 +0200 Subject: [PATCH] fix: safer logging, working setup on macOS, current SDK - Stop logging tokens, claims and the user's profile in app.py. - Fix /api_demo crashing when you're not signed in, and don't crash the other pages if user info can't be loaded. - Add .env to .gitignore so Kinde secrets don't get committed. - Run on localhost:5001 by default (port 5000 is taken by AirPlay on macOS, and the app must be opened on the same host as the redirect URI). - README and .env.example: use KINDE_HOST and SECRET_KEY, which the SDK actually reads, and drop variables nothing uses. - Require kinde-python-sdk ~=2.4 and Flask-Session >=0.6.0 (Flask 3 support), skipping the broken 0.7.0. --- .env.example | 49 ++++++++++++++++++++---------------------------- .gitignore | 4 +++- README.md | 47 +++++++++++++++++++++------------------------- app.py | 43 ++++++++++++++++++++---------------------- requirements.txt | 4 ++-- 5 files changed, 66 insertions(+), 81 deletions(-) diff --git a/.env.example b/.env.example index 8c6483d..8eab8e4 100644 --- a/.env.example +++ b/.env.example @@ -1,36 +1,27 @@ -# Kinde Application Configuration -# Get these values from your Kinde application settings +# Kinde Flask starter kit +# Copy this file to .env and fill in the values from your Kinde application. +# .env is in .gitignore, so your secrets stay out of git. + +# Your Kinde application (App Keys page) KINDE_CLIENT_ID= KINDE_CLIENT_SECRET= - -# Redirect URI configurations -# Update these URLs to match your application's deployment -KINDE_REDIRECT_URI=http://localhost:5000/callback -LOGOUT_REDIRECT_URL=http://localhost:5000/ -KINDE_CALLBACK_URL=http://localhost:5000/callback - -# Kinde Host Configuration -# Replace with your actual Kinde subdomain KINDE_HOST=https://.kinde.com -KINDE_ISSUER_URL=https://.kinde.com -KINDE_DOMAIN=.kinde.com +KINDE_REDIRECT_URI=http://localhost:5001/callback +# Optional: only if you call your own API with the access token +# KINDE_AUDIENCE= -# OAuth Configuration -KINDE_AUDIENCE= -GRANT_TYPE=AUTHORIZATION_CODE_WITH_PKCE -# Generate a random string for code verifier (43-128 characters) -CODE_VERIFIER= +# Management API (optional, used by the /helpers and /api_demo pages) +KINDE_DOMAIN=.kinde.com +KINDE_MANAGEMENT_CLIENT_ID= +KINDE_MANAGEMENT_CLIENT_SECRET= -# Flask Application Configuration -TEMPLATES_AUTO_RELOAD=True -SESSION_TYPE=filesystem -SESSION_PERMANENT=False -# Generate a secure random secret key for Flask sessions +# Flask sessions. Generate a key with: +# python -c "import secrets; print(secrets.token_hex(32))" SECRET_KEY= +# Optional: where session files are kept (a temporary folder is used if not set) +# SESSION_FILE_DIR=./flask_session -# Management API Configuration (Optional) -# Only needed if you're using Kinde Management API -MGMT_API_CLIENT_ID= -MGMT_API_CLIENT_SECRET= -KINDE_MANAGEMENT_CLIENT_ID= -KINDE_MANAGEMENT_CLIENT_SECRET= +# Run on localhost:5001. Port 5000 is used by AirPlay on macOS, and the app must be +# opened on the same host as KINDE_REDIRECT_URI (localhost, not 127.0.0.1). +FLASK_RUN_HOST=localhost +FLASK_RUN_PORT=5001 diff --git a/.gitignore b/.gitignore index 125ea13..c7872fc 100644 --- a/.gitignore +++ b/.gitignore @@ -243,4 +243,6 @@ Temporary Items .apdisk # Flask session -flask_session \ No newline at end of file +flask_session +# Local environment (Kinde credentials and secrets) +.env diff --git a/README.md b/README.md index 819d6c2..242387d 100644 --- a/README.md +++ b/README.md @@ -16,52 +16,47 @@ The minimum required version of Python is 3.9. This starter kit uses Kinde Python SDK v2, which simplifies the configuration by using environment variables instead of a config file. -Create a `.env` file in the root directory with the following variables from your Kinde `App Keys` page: +Copy `.env.example` to `.env` and fill in the values from your Kinde `App Keys` page: -```env -# Kinde Flask Starter Kit Environment Variables -# Copy this template and fill in your actual values +```console +$ cp .env.example .env +``` -# Required: Your Kinde application credentials -KINDE_CLIENT_ID=your_client_id_here -KINDE_CLIENT_SECRET=your_client_secret_here -KINDE_REDIRECT_URI=http://localhost:5000/callback -KINDE_DOMAIN=https://your-subdomain.kinde.com +`.env` is already in `.gitignore`, so your secrets stay out of git. -# Optional: Management API credentials (for enhanced features) -KINDE_MANAGEMENT_CLIENT_ID=your_management_client_id_here -KINDE_MANAGEMENT_CLIENT_SECRET=your_management_client_secret_here +### Environment variables -# Flask configuration -FLASK_SECRET_KEY=your-secret-key-here -``` +- **KINDE_CLIENT_ID** - Your Kinde client ID +- **KINDE_CLIENT_SECRET** - Your Kinde client secret +- **KINDE_HOST** - Your Kinde domain with `https://` (e.g. `https://your-subdomain.kinde.com`) +- **KINDE_REDIRECT_URI** - The callback URL: `http://localhost:5001/callback` +- **SECRET_KEY** - A random key for Flask sessions. Generate one with `python -c "import secrets; print(secrets.token_hex(32))"` -### Required Environment Variables: +For the Management API pages (`/helpers` and `/api_demo`), also set: -- **KINDE_CLIENT_ID** - Your Kinde client ID -- **KINDE_CLIENT_SECRET** - Your Kinde client secret -- **KINDE_REDIRECT_URI** - The callback URL (typically `http://localhost:5000/callback`) -- **KINDE_DOMAIN** - Your Kinde domain (e.g., `https://your-subdomain.kinde.com`) -- **KINDE_MANAGEMENT_CLIENT_ID** - Your Kinde management client ID (for Management API features) +- **KINDE_DOMAIN** - Your Kinde domain without `https://` (e.g. `your-subdomain.kinde.com`) +- **KINDE_MANAGEMENT_CLIENT_ID** - Your Kinde management client ID - **KINDE_MANAGEMENT_CLIENT_SECRET** - Your Kinde management client secret -> **Note**: Make sure to add `.env` to your `.gitignore` file to keep your secrets secure. - ## Set your Callback and Logout URLs Your user will be redirected to Kinde to authenticate. After they have logged in or registered they will be redirected back to your Flask application. You need to specify in Kinde which URL you would like your user to be redirected to in order to authenticate your app. -On the App Keys page set `Allowed callback URLs` to `http://localhost:5000/callback` +On the App Keys page set `Allowed callback URLs` to `http://localhost:5001/callback` > Important! This is required for your users to successfully log in to your app. -You will also need to set the URL they will be redirected to upon logout. Set the `Allowed logout redirect URLs` to `http://localhost:5000`. +You will also need to set the URL they will be redirected to upon logout. Set the `Allowed logout redirect URLs` to `http://localhost:5001`. ## Start the app -Run `flask run` and navigate to `http://localhost:5000`. +Run `flask run` and navigate to `http://localhost:5001`. + +The app runs on port 5001 because port 5000 is used by AirPlay on macOS. The port and host are set in `.env` (`FLASK_RUN_PORT` and `FLASK_RUN_HOST`). + +> Open the app at `http://localhost:5001`, not `http://127.0.0.1:5001`. Your browser keeps separate cookies for the two, so if you start the login on one and Kinde sends you back to the other, the login fails with an invalid state error. Click on `Sign up` and register your first user for your business! diff --git a/app.py b/app.py index 1da64ea..b45f689 100644 --- a/app.py +++ b/app.py @@ -38,21 +38,14 @@ def get_authorized_data(): logger.info("get_authorized_data: User is authenticated, getting user info") user = kinde_oauth.get_user_info() - logger.info(f"get_authorized_data: User: {user}") - + if not user: logger.warning("get_authorized_data: Failed to get user info") return None - - logger.info(f"get_authorized_data: Successfully retrieved user info for user ID: {user.get('id', 'unknown')}") - logger.info(f"get_authorized_data: Full user data: {user}") - id_token = tokens.get_token_manager().get_id_token() - logger.info(f"get_authorized_data: ID token: {id_token}") - access_token = tokens.get_token_manager().get_access_token() - logger.info(f"get_authorized_data: Access token: {access_token}") - claims = tokens.get_token_manager().get_claims() - logger.info(f"get_authorized_data: Claims: {claims}") - + + # Never log tokens, claims or the user's profile: logs are often shared or stored + logger.info("get_authorized_data: Successfully retrieved user info") + user_data = { "id": user.get("id"), "user_given_name": user.get("given_name"), @@ -60,8 +53,7 @@ def get_authorized_data(): "user_email": user.get("email"), "user_picture": user.get("picture"), } - - logger.info(f"get_authorized_data: Returning user data: {user_data}") + return user_data @@ -98,8 +90,9 @@ def get_management_client(): def index(): data = {"current_year": date.today().year} template = "logged_out.html" - if kinde_oauth.is_authenticated(): - data.update(get_authorized_data()) + user_data = get_authorized_data() + if user_data: + data.update(user_data) template = "home.html" return render_template(template, **data) @@ -110,9 +103,9 @@ def get_details(): template = "logged_out.html" data = {"current_year": date.today().year} - if kinde_oauth.is_authenticated(): - data = {"current_year": date.today().year} - data.update(get_authorized_data()) + user_data = get_authorized_data() + if user_data: + data.update(user_data) data["access_token"] = tokens.get_token_manager().get_access_token() template = "details.html" @@ -125,9 +118,9 @@ def get_helper_functions(): data = {"current_year": date.today().year} - if kinde_oauth.is_authenticated(): - data.update(get_authorized_data()) - #print(kinde_client.configuration.access_token) + user_data = get_authorized_data() + if user_data: + data.update(user_data) try: # Handle async calls using event loop @@ -198,7 +191,11 @@ def get_api_demo(): template = "api_demo.html" data = {"current_year": date.today().year} - data.update(get_authorized_data()) + user_data = get_authorized_data() + if not user_data: + return render_template("logged_out.html", **data) + data.update(user_data) + if kinde_oauth.is_authenticated(): management_client = get_management_client() diff --git a/requirements.txt b/requirements.txt index 6ce9532..92fdc2a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ python-dotenv>=1.0.0 Flask~=3.0.0 -kinde-python-sdk~=2.0.8 -Flask-Session~=0.5.0 +kinde-python-sdk~=2.4 +Flask-Session>=0.6.0,!=0.7.0,<1.0.0 Werkzeug~=3.0.0