@@ -16,6 +16,7 @@ Supported Authentication Types
1616 It's the web server responsibility to authenticate the user, useful for intranet sites, when the server (Apache, Nginx)
1717 is configured to use kerberos, no need for the user to login with username and password on F.A.B.
1818:OAUTH: Authentication using OAUTH (v1 or v2). You need to install authlib.
19+ :SAML: Authentication using SAML 2.0 (e.g., Microsoft Entra ID, Okta, OneLogin). You need to install python3-saml.
1920
2021.. note ::
2122 **Deprecated Authentication Types (Removed in Flask-AppBuilder 5.0+) **
@@ -31,15 +32,16 @@ The session is preserved and encrypted using Flask-Login.
3132Authentication Methods
3233----------------------
3334
34- You can choose one from 4 authentication methods. Configure the method to be used
35+ You can choose one from 5 authentication methods. Configure the method to be used
3536on the **config.py ** (when using the create-app, or following the proposed app structure). First the
3637configuration imports the constants for the authentication methods::
3738
3839 from flask_appbuilder.security.manager import (
3940 AUTH_DB,
4041 AUTH_LDAP,
4142 AUTH_OAUTH,
42- AUTH_REMOTE_USER
43+ AUTH_REMOTE_USER,
44+ AUTH_SAML,
4345 )
4446
4547Next you will use the **AUTH_TYPE ** key to choose the type::
@@ -438,6 +440,138 @@ Therefore, you can send tweets, post on the users Facebook, retrieve the user's
438440Take a look at the `example <https://github.com/dpgaspar/Flask-AppBuilder/tree/master/examples/oauth >`_
439441to get an idea of a simple use for this.
440442
443+ Authentication: SAML
444+ --------------------
445+
446+ This method will authenticate users via SAML 2.0 identity providers such as
447+ Microsoft Entra ID (formerly Azure AD), Okta, OneLogin, etc.
448+
449+ .. note :: To use SAML you need to install `python3-saml <https://github.com/SAML-Toolkits/python3-saml>`_:
450+ ``pip install flask-appbuilder[saml] ``
451+
452+ Configure your SAML providers and SP settings in **config.py **::
453+
454+ AUTH_TYPE = AUTH_SAML
455+
456+ # registration configs
457+ AUTH_USER_REGISTRATION = True
458+ AUTH_USER_REGISTRATION_ROLE = "Public"
459+
460+ # Sync roles at login from SAML assertion
461+ AUTH_ROLES_SYNC_AT_LOGIN = True
462+
463+ # Map SAML group names to FAB roles
464+ AUTH_ROLES_MAPPING = {
465+ "admins": ["Admin"],
466+ "users": ["Public"],
467+ }
468+
469+ # SAML Identity Providers
470+ SAML_PROVIDERS = [
471+ {
472+ "name": "entra_id",
473+ "icon": "fa-microsoft",
474+ "idp": {
475+ "entityId": "https://sts.windows.net/<TENANT_ID>/",
476+ "singleSignOnService": {
477+ "url": "https://login.microsoftonline.com/<TENANT_ID>/saml2",
478+ "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
479+ },
480+ "singleLogoutService": {
481+ "url": "https://login.microsoftonline.com/<TENANT_ID>/saml2",
482+ "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
483+ },
484+ "x509cert": "<IDP_CERTIFICATE_BASE64>",
485+ },
486+ "attribute_mapping": {
487+ "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "email",
488+ "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname": "first_name",
489+ "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname": "last_name",
490+ "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "username",
491+ "http://schemas.microsoft.com/ws/2008/06/identity/claims/groups": "role_keys",
492+ },
493+ },
494+ ]
495+
496+ # Global SAML Service Provider configuration
497+ SAML_CONFIG = {
498+ "strict": True,
499+ "debug": False,
500+ "sp": {
501+ "entityId": "https://myapp.example.com/saml/metadata/",
502+ "assertionConsumerService": {
503+ "url": "https://myapp.example.com/saml/acs/",
504+ "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
505+ },
506+ "singleLogoutService": {
507+ "url": "https://myapp.example.com/saml/slo/",
508+ "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
509+ },
510+ "NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
511+ "x509cert": "",
512+ # "privateKey": "",
513+ },
514+ "security": {
515+ "nameIdEncrypted": False,
516+ "authnRequestsSigned": False,
517+ "logoutRequestSigned": False,
518+ "logoutResponseSigned": False,
519+ "signMetadata": False,
520+ "wantMessagesSigned": False,
521+ "wantAssertionsSigned": True,
522+ "wantAssertionsEncrypted": False,
523+ "wantNameId": True,
524+ "wantNameIdEncrypted": False,
525+ "wantAttributeStatement": True,
526+ },
527+ }
528+
529+ Each SAML provider entry has the following keys:
530+
531+ :name: A unique name for the identity provider.
532+ :icon: A Font Awesome icon class for the login button.
533+ :idp: The IdP SAML metadata (entityId, SSO/SLO URLs, and signing certificate).
534+ :attribute_mapping: Maps SAML assertion attribute names (left) to FAB user fields (right).
535+ Supported FAB fields: ``username ``, ``email ``, ``first_name ``, ``last_name ``, ``role_keys ``.
536+
537+ The ``SAML_CONFIG `` dict holds the global Service Provider settings. The ``sp `` section defines
538+ your application's SAML endpoints. These URLs must match what you configure on the IdP side.
539+
540+ SAML Endpoints
541+ ~~~~~~~~~~~~~~
542+
543+ The following endpoints are automatically registered:
544+
545+ - ``/login/ `` — Login page with IdP selection (or auto-redirect for single IdP)
546+ - ``/login/<idp> `` — Initiate SSO with a specific IdP
547+ - ``/saml/acs/ `` — Assertion Consumer Service (receives SAML responses)
548+ - ``/saml/slo/ `` — Single Logout endpoint
549+ - ``/saml/metadata/ `` — SP metadata XML (configure this URL on your IdP)
550+
551+ SAML Role Mapping
552+ ~~~~~~~~~~~~~~~~~
553+
554+ You can map SAML group claims to FAB roles, just like with OAuth and LDAP::
555+
556+ AUTH_ROLES_MAPPING = {
557+ "admins": ["Admin"],
558+ "users": ["User"],
559+ }
560+
561+ AUTH_ROLES_SYNC_AT_LOGIN = True
562+
563+ PERMANENT_SESSION_LIFETIME = 1800
564+
565+ The ``role_keys `` field in ``attribute_mapping `` defines which SAML attribute contains the
566+ user's group memberships.
567+
568+ You can also use JMESPath expressions for dynamic role assignment::
569+
570+ AUTH_USER_REGISTRATION_ROLE_JMESPATH = "role_keys[0]"
571+
572+ Take a look at the `SAML example <https://github.com/dpgaspar/Flask-AppBuilder/tree/master/examples/saml >`_
573+
574+
441575Authentication: Rate limiting
442576-----------------------------
443577
@@ -448,6 +582,47 @@ The rate can be changed by adjusting ``AUTH_RATE_LIMIT`` to, for example, ``1 pe
448582at the `documentation <https://flask-limiter.readthedocs.io/en/stable/ >`_ of Flask-Limiter for more options and
449583examples.
450584
585+ Authentication: API Keys
586+ ------------------------
587+
588+ FAB supports API key authentication as an alternative to JWT tokens. API keys are long-lived
589+ credentials that can be used for service-to-service communication or automation.
590+
591+ **Enabling API Key Authentication **
592+
593+ Set the following in your config::
594+
595+ FAB_API_KEY_ENABLED = True
596+
597+ **Creating API Keys **
598+
599+ API keys are managed through the ``SecurityManager ``. You can create keys programmatically::
600+
601+ from flask import current_app
602+
603+ sm = current_app.appbuilder.sm
604+ api_key = sm.create_api_key(user=user, name="my-service-key")
605+
606+ The returned key string should be stored securely -- it cannot be retrieved again after creation.
607+
608+ **Using API Keys **
609+
610+ Pass the API key as a Bearer token in the ``Authorization `` header::
611+
612+ $ curl http://localhost:8080/api/v1/example/private \
613+ -H "Authorization: Bearer sst_<YOUR_API_KEY>"
614+
615+ API keys use the same permission system as regular users. The key inherits the roles and
616+ permissions of the user it belongs to.
617+
618+ **Configuration Options **
619+
620+ The following configuration options are available:
621+
622+ - ``FAB_API_KEY_ENABLED `` -- Set to ``True `` to enable API key authentication (default: ``False ``).
623+ - ``FAB_API_KEY_PREFIXES `` -- List of prefixes that identify API keys vs JWT tokens
624+ (default: ``["sst_"] ``).
625+
451626Role based
452627----------
453628
@@ -849,6 +1024,9 @@ F.A.B. uses a different user view for each authentication method
8491024
8501025:UserDBModelView: For database auth method
8511026:UserLDAPModelView: For LDAP auth method
1027+ :UserOAuthModelView: For OAuth auth method
1028+ :UserRemoteUserModelView: For Remote User auth method
1029+ :UserSAMLModelView: For SAML auth method
8521030
8531031You can extend or create from scratch your own, and then tell F.A.B. to use them instead, by overriding their
8541032correspondent lower case properties on **SecurityManager ** (just like on the given example).
@@ -882,6 +1060,7 @@ If you're using:
8821060:AUTH_LDAP: Extend UserLDAPModelView
8831061:AUTH_REMOTE_USER: Extend UserRemoteUserModelView
8841062:AUTH_OAUTH: Extend UserOAuthModelView
1063+ :AUTH_SAML: Extend UserSAMLModelView
8851064
8861065So using AUTH_DB::
8871066
@@ -956,6 +1135,8 @@ Note that this is for AUTH_DB, so if you're using:
9561135:AUTH_DB: Override userdbmodelview
9571136:AUTH_LDAP: Override userldapmodelview
9581137:AUTH_REMOTE_USER: Override userremoteusermodelview
1138+ :AUTH_OAUTH: Override useroauthmodelview
1139+ :AUTH_SAML: Override usersamlmodelview
9591140
9601141Finally (as shown on the previous example) tell F.A.B. to use your SecurityManager class, so when initializing
9611142**AppBuilder ** (on __init__.py)::
0 commit comments