{"id":7240,"library":"flask-principal","title":"Flask-Principal","description":"Flask-Principal is an extension for Flask that provides identity management for users, enabling flexible authorization based on 'Needs' and 'Permissions'. The latest stable version is 0.4.0, released in 2012, and the library is largely unmaintained. It uses a signal-based approach to load user identities and their associated permissions.","status":"deprecated","version":"0.4.0","language":"en","source_language":"en","source_url":"https://github.com/mattupstate/flask-principal","tags":["flask","authorization","permissions","identity","access-control"],"install":[{"cmd":"pip install Flask-Principal","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core web framework dependency.","package":"Flask","optional":false}],"imports":[{"note":"The 'flaskext' namespace was used in older Flask extensions but is deprecated.","wrong":"from flaskext.principal import Principal","symbol":"Principal","correct":"from flask_principal import Principal"},{"symbol":"Identity","correct":"from flask_principal import Identity"},{"symbol":"AnonymousIdentity","correct":"from flask_principal import AnonymousIdentity"},{"symbol":"Permission","correct":"from flask_principal import Permission"},{"symbol":"Need","correct":"from flask_principal import Need"},{"symbol":"RoleNeed","correct":"from flask_principal import RoleNeed"},{"symbol":"UserNeed","correct":"from flask_principal import UserNeed"},{"symbol":"current_identity","correct":"from flask_principal import current_identity"},{"symbol":"identity_changed","correct":"from flask_principal import identity_changed"},{"symbol":"identity_loaded","correct":"from flask_principal import identity_loaded"}],"quickstart":{"code":"import os\nfrom flask import Flask, session, g, redirect, url_for\nfrom flask_principal import Principal, Identity, AnonymousIdentity, \\\n                            identity_changed, identity_loaded, \\\n                            current_identity, \\\n                            Need, UserNeed, RoleNeed, Permission\n\n# Initialize Flask app\napp = Flask(__name__)\napp.secret_key = os.environ.get('FLASK_SECRET_KEY', 'default_secret_key')\n\n# Initialize Flask-Principal\nprincipals = Principal(app)\n\n# Define a permission for 'admin' role\nadmin_permission = Permission(RoleNeed('admin'))\n\n@app.before_request\ndef load_identity_from_session():\n    # Load identity from session or create an anonymous one\n    if 'identity_id' in session:\n        g.identity = Identity(session['identity_id'])\n        # Signal that the identity has loaded\n        identity_changed.send(app, identity=g.identity)\n    else:\n        g.identity = AnonymousIdentity()\n\n@identity_loaded.connect_via(app)\ndef on_identity_loaded(sender, identity):\n    # This signal is fired when an identity is loaded (or changed)\n    # Use this to add Needs to the identity based on your application logic\n    if identity.id:\n        # Example: user_id 1 is an admin, others are regular users\n        if identity.id == 1:\n            identity.provides.add(RoleNeed('admin'))\n        identity.provides.add(UserNeed(identity.id)) # All logged-in users get their UserNeed\n    # For anonymous users, no specific Needs are added here by default\n\n@app.route('/login/<int:user_id>')\ndef login(user_id):\n    # Simulate a login: set identity in session and emit signal\n    session['identity_id'] = user_id\n    identity_changed.send(app, identity=Identity(user_id))\n    return f'Logged in as User {user_id}. <a href=\"{url_for(\"profile\")}\">Go to profile</a> <a href=\"{url_for(\"admin_dashboard\")}\">Go to admin dashboard</a>'\n\n@app.route('/logout')\ndef logout():\n    # Simulate a logout: clear session and emit anonymous identity signal\n    if 'identity_id' in session:\n        del session['identity_id']\n    identity_changed.send(app, identity=AnonymousIdentity())\n    return 'Logged out. <a href=\"{url_for(\"profile\")}\">Go to profile</a>'\n\n@app.route('/')\n@app.route('/profile')\ndef profile():\n    if current_identity.is_authenticated():\n        return f'Hello, User {current_identity.id}! You are authenticated.' \\\n               f' Role: {\"Admin\" if admin_permission.can() else \"User\"}.'\n    return 'Hello, Anonymous User! You are not logged in.'\n\n@app.route('/admin')\n@admin_permission.require() # This decorator enforces the 'admin' permission\ndef admin_dashboard():\n    return f'Welcome to the Admin Dashboard, User {current_identity.id}!'\n\nif __name__ == '__main__':\n    # For local testing, ensure a secret key is set\n    if 'FLASK_SECRET_KEY' not in os.environ:\n        print(\"WARNING: FLASK_SECRET_KEY environment variable not set. Using a default for demonstration.\")\n    app.run(debug=True)","lang":"python","description":"This quickstart demonstrates how to set up Flask-Principal with an example Flask application. It includes routes for logging in/out, a profile page, and an admin dashboard protected by a 'RoleNeed'. The `identity_changed` signal is used to update the current identity, and `identity_loaded` is used to assign `Needs` (like 'admin' role) to the identity. Ensure `FLASK_SECRET_KEY` is set for production."},"warnings":[{"fix":"Consider migrating to Flask-Login for authentication and implementing authorization logic with custom decorators or a more modern library.","message":"Flask-Principal is largely unmaintained, with its last release (0.4.0) dating back to 2012. It may not be compatible with newer Flask versions or Python features, and there are no active security updates. Modern Flask applications are advised to use more actively maintained authentication and authorization libraries like Flask-Login (for authentication) combined with custom decorators for role-based access control, or comprehensive solutions for JWT/session management.","severity":"deprecated","affected_versions":"<=0.4.0"},{"fix":"Thoroughly test on your target Python 3 version if you must use this library. Prefer alternatives for new projects.","message":"Flask-Principal was originally developed for Python 2. While basic functionality might work on Python 3, subtle compatibility issues or unhandled edge cases may arise due to differences in string handling, standard library changes, or other Python 2/3 specific behaviors. The library's `requires_python` metadata is `None`, indicating no explicit Python 3 support was declared.","severity":"gotcha","affected_versions":"All versions on Python 3.x"},{"fix":"Implement a robust authentication system to manage user sessions and login states, then use Flask-Principal's `Identity` object to represent the authenticated user.","message":"Flask-Principal handles *authorization* (what a user can do), not *authentication* (who the user is). You must integrate it with a separate authentication mechanism (e.g., Flask-Login, a custom session manager, or OAuth) to establish the user's identity before Principal can assign and check permissions.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure that `identity_changed.send()` is always called within a request context or an explicitly pushed application context (e.g., `with app.app_context():`).","message":"The signal-based nature of `identity_changed` and `identity_loaded` means they must be sent within an active Flask application context (`app.app_context()` or during a request). Calling `identity_changed.send()` outside of an app context will raise a `RuntimeError`.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Ensure all Flask-Principal operations, especially signal emissions, are performed within an active request context or by explicitly pushing an application context: `with app.app_context(): identity_changed.send(...)`.","cause":"The `identity_changed.send()` method or other Principal operations were called outside of an active Flask application context (e.g., in a background thread or a script without a context pushed).","error":"RuntimeError: Working outside of application context."},{"fix":"Verify that `principals = Principal(app)` is correctly called during your application setup. If using an app factory, ensure `Principal()` is initialized with `app` *within* the factory or with `Principal().init_app(app)`.","cause":"Flask-Principal was either not initialized with your Flask application (`principals = Principal(app)` was omitted or called incorrectly), or you are attempting to use Principal features (like `current_identity`) outside of a request where the application context might not be properly set up or associated with the Principal extension.","error":"AssertionError: This Principal extension is not registered to the current application."},{"fix":"Inspect your `identity_loaded` signal handler to ensure it correctly populates `identity.provides` with the appropriate `Need` objects for the current user. Double-check that the `Need` defined in your `Permission` (e.g., `Permission(RoleNeed('admin'))`) exactly matches the `Need` added to the identity.","cause":"The `current_identity` does not possess the required `Need` for the permission being checked. This often happens if the `identity_loaded` signal handler doesn't correctly add `Needs` to the identity's `provides` set, or if the `Need` definition in the permission does not match what's provided.","error":"Access denied / Permission not granted / @requires_role decorator not working."}]}