You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by "albundy83 (via GitHub)" <gi...@apache.org> on 2026/02/19 10:30:18 UTC

[PR] feat: Improve oauth doc [superset]

albundy83 opened a new pull request, #38092:
URL: https://github.com/apache/superset/pull/38092

   <!---
   Please write the PR title following the conventions at https://www.conventionalcommits.org/en/v1.0.0/
   Example:
   fix(dashboard): load charts correctly
   -->
   
   ### SUMMARY
   Improve basic oauth documentation, explain a full scenario with groups assignment and show how to really implement logout from your oauth provider with a correct return uri.
   
   It could also help to fix some issue / question ([here](https://github.com/apache/superset/issues/24713) or [here](https://github.com/apache/superset/issues/33609) for example)
   
   ### ADDITIONAL INFORMATION
   <!--- Check any relevant boxes with "x" -->
   <!--- HINT: Include "Fixes #nnn" if you are fixing an existing issue -->
   - [x] Has associated issue:
   - [ ] Required feature flags:
   - [ ] Changes UI
   - [ ] Includes DB Migration (follow approval process in [SIP-59](https://github.com/apache/superset/issues/13351))
     - [ ] Migration is atomic, supports rollback & is backwards-compatible
     - [ ] Confirm DB migration upgrade and downgrade tested
     - [ ] Runtime estimates and downtime expectations provided
   - [ ] Introduces new feature or API
   - [ ] Removes existing feature or API
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3936030629

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4924918663

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3934982528

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "albundy83 (via GitHub)" <gi...@apache.org>.
albundy83 commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3935175564

   /review
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r3550391271


##########
docs/admin_docs/security/oauth.mdx:
##########
@@ -0,0 +1,183 @@
+---
+title: OAuth Configuration
+sidebar_position: 4
+---
+
+# Keycloak
+
+## Complete example: Keycloak with PKCE and group mapping
+
+This example demonstrates a complete Keycloak integration with Superset, including group-to-role mapping, single logout with Keycloak, and PKCE support.
+
+First, create a Secret containing the following values:
+
+* `CLIENT_ID`
+* `CLIENT_SECRET`
+* `OIDC_ISSUER`
+
+The Keycloak client must be configured to support the PKCE flow.
+
+To enable PKCE, set **Proof Key for Code Exchange Code Challenge Method** to **S256** under:
+
+`Clients -> my_superset_clientid -> Advanced -> Advanced settings`
+
+This implementation correctly handles the case where a user successfully authenticates with Keycloak but does not belong to any of the configured groups.
+
+The following snippet defines the mapping between Keycloak groups and Superset roles:
+
+```python
+AUTH_ROLES_MAPPING = {
+    f'{CLIENT_ID}_admin': ['Admin'],
+    f'{CLIENT_ID}_alpha': ['Alpha'],
+    f'{CLIENT_ID}_gamma': ['Gamma'],
+    f'{CLIENT_ID}_public': ['Public'],
+}
+```
+
+If a user does not belong to any of the mapped groups, they will be redirected back to the login page.
+
+Make sure the following groups exist in Keycloak and that users are assigned to at least one of them:
+
+* `<my_superset_clientid>_admin`
+* `<my_superset_clientid>_alpha`
+* `<my_superset_clientid>_gamma`
+* `<my_superset_clientid>_public`
+
+## Helm chart configuration
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://mykeycloak.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',

Review Comment:
   **Suggestion:** The PKCE option is configured under `client_kwargs`, but Flask-AppBuilder/Authlib expects `code_challenge_method` at the `remote_app` level; in this location it can be ignored, so the example may run without PKCE even though the docs say PKCE is enabled. [api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   ❌ PKCE not enabled despite documentation, weakening OAuth security.
   ⚠️ Operators misled about Keycloak client PKCE configuration.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Follow the Keycloak Helm example in `docs/admin_docs/security/oauth.mdx:71-100`,
   copying `OAUTH_PROVIDERS` and related config into your `superset_config.py` or Helm
   `configOverrides` as documented.
   
   2. Note that in this example the PKCE option is set under `client_kwargs` at lines 93-96
   (`code_challenge_method': 'S256'`), whereas the PKCE docs in
   `docs/admin_docs/configuration/configuring-superset.mdx:377-386` configure
   `code_challenge_method` directly inside the `remote_app` dict.
   
   3. Start Superset with this configuration and initiate a Keycloak login; the OAuth client
   used by Flask-AppBuilder is built from `OAUTH_PROVIDERS` (see
   `docs/admin_docs_versioned_docs/version-6.1.0/configuration/configuring-superset.mdx:282-289`
   which describes this wiring).
   
   4. Inspect the authorization request sent to Keycloak (for example via browser developer
   tools); because `code_challenge_method` is not at the expected level in the config, the
   request lacks PKCE parameters (`code_challenge` and `code_challenge_method`), so the flow
   runs without PKCE even though the documentation claims it is enabled.
   ```
   </details>
   
   [![Fix in Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=254e4bb3973640f8929f1cc7947d0813&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [![Fix in VSCode Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=254e4bb3973640f8929f1cc7947d0813&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/admin_docs/security/oauth.mdx
   **Line:** 93:96
   **Comment:**
   	*Api Mismatch: The PKCE option is configured under `client_kwargs`, but Flask-AppBuilder/Authlib expects `code_challenge_method` at the `remote_app` level; in this location it can be ignored, so the example may run without PKCE even though the docs say PKCE is enabled.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=55c98b1c9c2da49419b64d50d1e538d1fd5b094e8ae50c36c4ed65db0959d770&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=55c98b1c9c2da49419b64d50d1e538d1fd5b094e8ae50c36c4ed65db0959d770&reaction=dislike'>👎</a>



##########
docs/admin_docs/security/oauth.mdx:
##########
@@ -0,0 +1,183 @@
+---
+title: OAuth Configuration
+sidebar_position: 4
+---
+
+# Keycloak
+
+## Complete example: Keycloak with PKCE and group mapping
+
+This example demonstrates a complete Keycloak integration with Superset, including group-to-role mapping, single logout with Keycloak, and PKCE support.
+
+First, create a Secret containing the following values:
+
+* `CLIENT_ID`
+* `CLIENT_SECRET`
+* `OIDC_ISSUER`
+
+The Keycloak client must be configured to support the PKCE flow.
+
+To enable PKCE, set **Proof Key for Code Exchange Code Challenge Method** to **S256** under:
+
+`Clients -> my_superset_clientid -> Advanced -> Advanced settings`
+
+This implementation correctly handles the case where a user successfully authenticates with Keycloak but does not belong to any of the configured groups.
+
+The following snippet defines the mapping between Keycloak groups and Superset roles:
+
+```python
+AUTH_ROLES_MAPPING = {
+    f'{CLIENT_ID}_admin': ['Admin'],
+    f'{CLIENT_ID}_alpha': ['Alpha'],
+    f'{CLIENT_ID}_gamma': ['Gamma'],
+    f'{CLIENT_ID}_public': ['Public'],
+}
+```
+
+If a user does not belong to any of the mapped groups, they will be redirected back to the login page.
+
+Make sure the following groups exist in Keycloak and that users are assigned to at least one of them:
+
+* `<my_superset_clientid>_admin`
+* `<my_superset_clientid>_alpha`
+* `<my_superset_clientid>_gamma`
+* `<my_superset_clientid>_public`
+
+## Helm chart configuration
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://mykeycloak.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    class CustomOAuthView(AuthOAuthView):
+        # Override the logout method to also log out from the OIDC provider
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            super().logout()
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+
+        # Override the authorized method to handle the OIDC callback and map groups to roles
+        @expose('/oauth-authorized/<provider>')
+        def oauth_authorized(self, provider):
+            # Step 1: exchange the authorization code for an access token
+            try:
+                resp = self.appbuilder.sm.oauth_remotes[provider].authorize_access_token()
+            except Exception as e:
+                log.exception(f'Error fetching access token: {e}')
+                return redirect(self.appbuilder.get_url_for_index)
+
+            # Step 2: fetch user info from the OIDC provider
+            userinfo = self.appbuilder.sm.get_oauth_user_info(provider, resp)

Review Comment:
   **Suggestion:** The userinfo fetch path can raise exceptions (`raise_for_status` or JSON/HTTP failures), but this call is outside the existing `try` block, so transient IdP errors will produce a 500 instead of a controlled redirect/error flow. [possible bug]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   ❌ OAuth callback can 500 on IdP userinfo errors.
   ⚠️ Users see generic crash instead of graceful login failure.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Use the Keycloak configuration example from `docs/admin_docs/security/oauth.mdx`,
   including `CustomOAuthView.oauth_authorized` (lines 122-154) and
   `CustomSsoSecurityManager.get_oauth_user_info` (lines 162-178) in your Superset
   configuration.
   
   2. A user completes authentication at Keycloak and is redirected to the callback endpoint
   `/oauth-authorized/keycloak`, which is exposed by `CustomOAuthView.oauth_authorized` at
   line 123.
   
   3. Simulate a transient failure on the userinfo endpoint configured as `OIDC_USERINFO_URL`
   (line 79), for example by stopping Keycloak or forcing it to return a 500 error; the call
   `oauth_remotes[provider].get(OIDC_USERINFO_URL)` or `me.raise_for_status()` at lines
   164-165 throws an exception.
   
   4. Because the only try/except block in `oauth_authorized` (lines 125-129) wraps the
   access-token exchange but not the userinfo call at line 132, the exception propagates out
   of the view and results in an HTTP 500 response instead of the intended redirect
   `self.appbuilder.get_url_for_index`, as confirmed by repository search which finds no
   additional wrapper around this method.
   ```
   </details>
   
   [![Fix in Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=b58ab9dfe22e4a43bc118803f92a94cc&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [![Fix in VSCode Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=b58ab9dfe22e4a43bc118803f92a94cc&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/admin_docs/security/oauth.mdx
   **Line:** 132:132
   **Comment:**
   	*Possible Bug: The userinfo fetch path can raise exceptions (`raise_for_status` or JSON/HTTP failures), but this call is outside the existing `try` block, so transient IdP errors will produce a 500 instead of a controlled redirect/error flow.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=8326b9034cee0e8db0ef61f382c51328caef4cbc7c3a64276648d366c4694880&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=8326b9034cee0e8db0ef61f382c51328caef4cbc7c3a64276648d366c4694880&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "netlify[bot] (via GitHub)" <gi...@apache.org>.
netlify[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3935760561

   ### <span aria-hidden="true">✅</span> Deploy Preview for *superset-docs-preview* ready!
   
   
   |  Name | Link |
   |:-:|------------------------|
   |<span aria-hidden="true">🔨</span> Latest commit | 06690c98ed8debc8eb083eeed2300495c69f5bd6 |
   |<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/projects/superset-docs-preview/deploys/69988424c942f20008368b00 |
   |<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-38092--superset-docs-preview.netlify.app](https://deploy-preview-38092--superset-docs-preview.netlify.app) |
   |<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTM4MDkyLS1zdXBlcnNldC1kb2NzLXByZXZpZXcubmV0bGlmeS5hcHAifQ.zfDAZOdy55PpNVcn1amhdMiywCQDK7m6O-48Kj2ElEM)<br /><br />_Use your smartphone camera to open QR code link._</details> |
   ---
   <!-- [superset-docs-preview Preview](https://deploy-preview-38092--superset-docs-preview.netlify.app) -->
   _To edit notification comments on pull requests, go to your [Netlify project configuration](https://app.netlify.com/projects/superset-docs-preview/configuration/notifications#deploy-notifications)._


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2827000469


##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,121 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+Clients -> <your-client-id> -> Advanced -> Advanced settings
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+    import requests
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = 'Public'
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    # Custom OAuth view to handle logout redirection to Keycloak
+    class CustomOAuthView(AuthOAuthView):
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+
+
+    class CustomSsoSecurityManager(SupersetSecurityManager):
+        # Override the default OAuth view with our custom one
+        authoauthview = CustomOAuthView
+
+        # Override the method to fetch groups from the token and map them to Superset roles
+        def get_oauth_user_info(self, provider, response):
+            if provider == 'keycloak':
+                headers = {'Authorization': f"Bearer {response['access_token']}"}
+                resp = requests.get(OIDC_USERINFO_URL, headers=headers, timeout=5)
+
+                log.info(f'userinfo: {me}')
+
+                groups = me.get('groups', [])
+                if not groups:
+                    groups = ['Public']
+
+                return {
+                    'username': me.get('preferred_username'),
+                    'email': me.get('email'),
+                    'first_name': me.get('given_name'),
+                    'last_name': me.get('family_name'),
+                    'role_keys': groups,
+                }
+            return {}
+
+    # Set our custom security manager
+    CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
+```
+

Review Comment:
   <div>
   
   
   <div id="suggestion">
   <div id="issue"><b>Incorrect OAuth role mapping</b></div>
   <div id="fix">
   
   The role_keys assignment in get_oauth_user_info does not match the AUTH_ROLES_MAPPING keys. The mapping uses prefixed keys like f'{CLIENT_ID}_admin', but role_keys is set to raw groups. This will prevent proper role assignment. Also, the default groups fallback uses 'Public' which doesn't correspond to any mapping key.
   </div>
   
   
   </div>
   
   
   
   
   <small><i>Code Review Run #c52ec5</i></small>
   </div><div>
   
   
   <div id="suggestion">
   <div id="issue"><b>Runtime error: undefined variable</b></div>
   <div id="fix">
   
   The variable 'me' is referenced throughout the method but never defined, which will cause a NameError at runtime when this OAuth path is executed. This appears to be an oversight in the documentation code example.
   </div>
   
   
   <details>
   <summary>
   <b>Code suggestion</b>
   </summary>
   <blockquote>Check the AI-generated fix before applying</blockquote>
   <div id="code">
   
   
   ```
    - resp = requests.get(OIDC_USERINFO_URL, headers=headers, timeout=5)
    - log.info(f'userinfo: {me}')
    + resp = requests.get(OIDC_USERINFO_URL, headers=headers, timeout=5)
    + me = resp.json()
    + log.debug(f'Received userinfo from OIDC provider for user {me.get(\"preferred_username\")}')
   ```
   
   </div>
   </details>
   
   
   
   </div>
   
   
   
   
   <small><i>Code Review Run #ae1161</i></small>
   </div>
   
   ---
   Should Bito avoid suggestions like this for future reviews? (<a href=https://alpha.bito.ai/home/ai-agents/review-rules>Manage Rules</a>)
   - [ ] Yes, avoid them



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "rusackas (via GitHub)" <gi...@apache.org>.
rusackas merged PR #38092:
URL: https://github.com/apache/superset/pull/38092


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "albundy83 (via GitHub)" <gi...@apache.org>.
albundy83 commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4015812954

   > Raising some concerns from a quick (AI assisted) review:
   > 
   > 1. Wrong file — This is landing in kubernetes.mdx, but the content is generic OAuth
   >    config that applies to any deployment. It deserves its own page or a spot in the
   >    auth/security docs, not buried mid-Kubernetes-install-guide.
   > 2. Very Keycloak-specific — The URL structure (/protocol/openid-connect/...), the
   >    `:::note` framing, and even the group key names are all Keycloak-specific. If it stays,
   >    it should be clearly scoped as a "Keycloak example" rather than a general OAuth guide
   >    improvement.
   > 3. `:::note` is the wrong container — The admonition wraps setup instructions, not a
   >    note. It'd be cleaner as a `:::tip` with a header like "Full example: Keycloak with PKCE
   >    and group mapping" or just as a regular `##` section.
   > 4. PR title — feat: Improve oauth doc should be docs(auth): add Keycloak PKCE and
   >    group-mapping example or similar.
   > 5. `get_url_for_index` missing `()` — Used in several redirect calls as
   >    `self.appbuilder.get_url_for_index` without calling it. If it's a method (not a
   >    property), those redirects would go to the function object, not the URL. Worth
   >    double-checking.
   > 
   > Lemme know what you think :) Meanwhile, running CI 🤞
   
   I will update my pull request according to your advice :)
   
   About the `get_url_for_index`, it's a property not a method I guess, [here](https://github.com/dpgaspar/Flask-AppBuilder/blob/v5.2.0/flask_appbuilder/security/views.py#L585) an example from the official source code.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2924764919


##########
docs/admin_docs/security/oauth.mdx:
##########
@@ -0,0 +1,182 @@
+---
+title: Oauth examples
+sidebar_position: 4
+---
+
+# Keycloak with PKCE, clean logout and groups mapping
+
+Here a full example using Keycloak as an OIDC provider with PKCE flow, clean logout and groups mapping to Superset roles.
+
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Keycloak must be configured to support PKCE flow, so you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+`Clients -> your-client-id -> Advanced -> Advanced settings`
+
+Logout is first handled by Superset to clear the session and then the user is redirected to Keycloak logout endpoint to complete the logout process on the OIDC provider side.
+It is important to clear the session in Superset first to avoid any issues with the OIDC provider.
+
+This code correctly handles the case where a user successfully authenticates with Keycloak but does not belong to any of the mapped groups.
+In that situation, the user is simply redirected back to the login page.
+
+## The Secret
+You can create the Secret with a manifest like this:
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+  name: superset-oauth-providers
+  namespace: my-beloved-superset-namespace
+stringData:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+type: Opaque
+```
+
+and you will need to reference it in your Helm values like this:
+```yaml
+envFromSecrets:
+  - superset-oauth-providers
+```
+
+Or you can directly set the environment variables in the values file like this:
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+```
+
+## The config overrides
+```yaml
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    class CustomOAuthView(AuthOAuthView):
+        # Override the logout method to also log out from the OIDC provider
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            super().logout()
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+
+        # Override the authorized method to handle the OIDC callback and map groups to roles
+        @expose('/oauth-authorized/<provider>')
+        def oauth_authorized(self, provider):
+            # Step 1: exchange the authorization code for an access token
+            try:
+                resp = self.appbuilder.sm.oauth_remotes[provider].authorize_access_token()
+            except Exception as e:
+                log.exception(f'Error fetching access token: {e}')
+                return redirect(self.appbuilder.get_url_for_index)
+
+            # Step 2: fetch user info from the OIDC provider
+            userinfo = self.appbuilder.sm.get_oauth_user_info(provider, resp)
+            role_keys = userinfo.get('role_keys', [])
+            known_groups = [g for g in role_keys if g in AUTH_ROLES_MAPPING]
+
+            # Step 3: if no valid groups, redirect to the home page without login
+            if not known_groups:
+                log.warning(
+                    f'No valid groups for user {userinfo.get("username")}, groups received: {role_keys}'
+                )
+                return redirect(self.appbuilder.get_url_for_index)
+
+            # Step 4: create or retrieve the user in the database with their roles
+            userinfo['role_keys'] = known_groups
+            user = self.appbuilder.sm.auth_user_oauth(userinfo)
+            if user is None:
+                log.warning(
+                    f'auth_user_oauth returned None for user {userinfo.get("username")}'
+                )
+                return redirect(self.appbuilder.get_url_for_index)
+
+            # Step 5: login and redirect to the app
+            login_user(user, remember=False)
+            return redirect(self.appbuilder.get_url_for_index)
+
+
+    class CustomSsoSecurityManager(SupersetSecurityManager):
+        # Override the default OAuth view with our custom one
+        authoauthview = CustomOAuthView
+
+        # Override the method to fetch groups from the token and map them to Superset roles
+        def get_oauth_user_info(self, provider, response):
+            if provider == 'keycloak':
+                me = self.appbuilder.sm.oauth_remotes[provider].get(OIDC_USERINFO_URL)
+                me.raise_for_status()
+                data = me.json()

Review Comment:
   **Suggestion:** The userinfo request raises on HTTP errors and currently has no local error handling, so transient IdP failures produce a 500 during login. Catch request/parsing errors in `get_oauth_user_info` and return an empty payload so the caller can handle it gracefully. [possible bug]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ OAuth login callback can return 500 errors.
   - ❌ Users may be blocked from signing in.
   ```
   </details>
   
   ```suggestion
                   try:
                       me = self.appbuilder.sm.oauth_remotes[provider].get(OIDC_USERINFO_URL)
                       me.raise_for_status()
                       data = me.json()
                   except Exception as e:
                       log.exception(f'Error fetching userinfo from OIDC provider: {e}')
                       return {}
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Use the documented custom manager in `docs/admin_docs/security/oauth.mdx:156-181`,
   which routes OAuth callback through `oauth_authorized()` (`:121-153`).
   
   2. During login, callback calls `get_oauth_user_info()` at `:131`, entering custom
   implementation at `:161`.
   
   3. If Keycloak userinfo endpoint responds with HTTP error or bad payload,
   `me.raise_for_status()` (`:164`) or `me.json()` (`:165`) raises.
   
   4. No local try/except exists around `:163-165`, and caller `oauth_authorized()` also does
   not wrap `:131`; request can return 500 and fail login.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/admin_docs/security/oauth.mdx
   **Line:** 163:165
   **Comment:**
   	*Possible Bug: The userinfo request raises on HTTP errors and currently has no local error handling, so transient IdP failures produce a 500 during login. Catch request/parsing errors in `get_oauth_user_info` and return an empty payload so the caller can handle it gracefully.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=e47be047201bc8e13b3275e2ebd63214fe2a4b035015cb40be5471937fa20195&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=e47be047201bc8e13b3275e2ebd63214fe2a4b035015cb40be5471937fa20195&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "albundy83 (via GitHub)" <gi...@apache.org>.
albundy83 closed pull request #38092: feat: Improve oauth doc
URL: https://github.com/apache/superset/pull/38092


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3926722264

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2827000469


##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,121 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+Clients -> <your-client-id> -> Advanced -> Advanced settings
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+    import requests
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = 'Public'
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    # Custom OAuth view to handle logout redirection to Keycloak
+    class CustomOAuthView(AuthOAuthView):
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+
+
+    class CustomSsoSecurityManager(SupersetSecurityManager):
+        # Override the default OAuth view with our custom one
+        authoauthview = CustomOAuthView
+
+        # Override the method to fetch groups from the token and map them to Superset roles
+        def get_oauth_user_info(self, provider, response):
+            if provider == 'keycloak':
+                headers = {'Authorization': f"Bearer {response['access_token']}"}
+                resp = requests.get(OIDC_USERINFO_URL, headers=headers, timeout=5)
+
+                log.info(f'userinfo: {me}')
+
+                groups = me.get('groups', [])
+                if not groups:
+                    groups = ['Public']
+
+                return {
+                    'username': me.get('preferred_username'),
+                    'email': me.get('email'),
+                    'first_name': me.get('given_name'),
+                    'last_name': me.get('family_name'),
+                    'role_keys': groups,
+                }
+            return {}
+
+    # Set our custom security manager
+    CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
+```
+

Review Comment:
   <div>
   
   
   <div id="suggestion">
   <div id="issue"><b>Incorrect OAuth role mapping</b></div>
   <div id="fix">
   
   The role_keys assignment in get_oauth_user_info does not match the AUTH_ROLES_MAPPING keys. The mapping uses prefixed keys like f'{CLIENT_ID}_admin', but role_keys is set to raw groups. This will prevent proper role assignment. Also, the default groups fallback uses 'Public' which doesn't correspond to any mapping key.
   </div>
   
   
   </div>
   
   
   
   
   <small><i>Code Review Run #c52ec5</i></small>
   </div>
   
   ---
   Should Bito avoid suggestions like this for future reviews? (<a href=https://alpha.bito.ai/home/ai-agents/review-rules>Manage Rules</a>)
   - [ ] Yes, avoid them



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4772243621

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4928572489

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "albundy83 (via GitHub)" <gi...@apache.org>.
albundy83 commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-6315364618

   But helm chart has been deprecated. I should just add example in oauth.mdx I guess


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2826935644


##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,122 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+Clients -> <your-client-id> -> Advanced -> Advanced settings
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+    import requests
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = 'Public'
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    # Custom OAuth view to handle logout redirection to Keycloak
+    class CustomOAuthView(AuthOAuthView):
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+
+
+    class CustomSsoSecurityManager(SupersetSecurityManager):
+        # Override the default OAuth view with our custom one
+        authoauthview = CustomOAuthView
+
+        # Override the method to fetch groups from the token and map them to Superset roles
+        def get_oauth_user_info(self, provider, response):
+            if provider == 'keycloak':
+                headers = {'Authorization': f"Bearer {response['access_token']}"}
+                resp = requests.get(OIDC_USERINFO_URL, headers=headers)
+                me = resp.json()
+
+                log.info(f'userinfo: {me}')
+
+                groups = me.get('groups', [])
+                if not groups:
+                    groups = ['Public']
+

Review Comment:
   **Suggestion:** The default group assigned when no groups are present (`"Public"`) does not match any key in the roles mapping (which uses names like `<CLIENT_ID>_public`), so users without a `groups` claim will not get any mapped roles, likely preventing them from receiving the intended default "Public" role. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Keycloak-based OAuth example misconfigures default group mapping.
   - ⚠️ Users without groups may miss intended Public permissions.
   - ⚠️ Role sync from IdP groups behaves inconsistently with docs.
   ```
   </details>
   
   ```suggestion
                       groups = [f'{CLIENT_ID}_public']
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Deploy Superset on Kubernetes using the Helm chart and copy the Keycloak example from
   `docs/docs/installation/kubernetes.mdx` under `### Setting up OAuth`, specifically the
   `configOverrides.enable_oauth` block that defines
   `CustomSsoSecurityManager.get_oauth_user_info` (around lines 396–424 in the final file).
   
   2. In Keycloak, configure the client with ID `my_superset_clientid` (matching `CLIENT_ID`
   in the example) and create realm roles / groups such that some user has no groups (or the
   `groups` claim is omitted/empty in the ID/access token / userinfo response).
   
   3. Log in to Superset via the Keycloak OAuth provider (the `keycloak` provider defined in
   `OAUTH_PROVIDERS` in the same config block). Superset invokes
   `CustomSsoSecurityManager.get_oauth_user_info('keycloak', response)` which calls the
   snippet at `docs/docs/installation/kubernetes.mdx:410–412` to derive `groups`.
   
   4. Because `groups` is empty, the code sets `groups = ['Public']`, but
   `AUTH_ROLES_MAPPING` (defined earlier in the same config block at lines ~378–383) only
   contains keys like `f'{CLIENT_ID}_public'`. As a result, Superset's role sync logic (in
   `superset/security/manager.py`, which reads `AUTH_ROLES_MAPPING`) cannot map `['Public']`
   to any Superset role, so the user does not receive the intended `Public` role derived from
   group mapping. This misalignment demonstrates the logic bug the suggestion addresses.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/docs/installation/kubernetes.mdx
   **Line:** 412:412
   **Comment:**
   	*Logic Error: The default group assigned when no groups are present (`"Public"`) does not match any key in the roles mapping (which uses names like `<CLIENT_ID>_public`), so users without a `groups` claim will not get any mapped roles, likely preventing them from receiving the intended default "Public" role.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=00040b1c110b801ce2a53b1fc25d726b52e114cf8a95569d315f725d27ec3527&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=00040b1c110b801ce2a53b1fc25d726b52e114cf8a95569d315f725d27ec3527&reaction=dislike'>👎</a>



##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,122 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+Clients -> <your-client-id> -> Advanced -> Advanced settings
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+    import requests
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = 'Public'
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    # Custom OAuth view to handle logout redirection to Keycloak
+    class CustomOAuthView(AuthOAuthView):
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+
+
+    class CustomSsoSecurityManager(SupersetSecurityManager):
+        # Override the default OAuth view with our custom one
+        authoauthview = CustomOAuthView
+
+        # Override the method to fetch groups from the token and map them to Superset roles
+        def get_oauth_user_info(self, provider, response):
+            if provider == 'keycloak':
+                headers = {'Authorization': f"Bearer {response['access_token']}"}
+                resp = requests.get(OIDC_USERINFO_URL, headers=headers)
+                me = resp.json()
+
+                log.info(f'userinfo: {me}')
+

Review Comment:
   **Suggestion:** Logging the entire `userinfo` payload at info level will store personally identifiable information (like emails and full profile data) in standard logs, which is a security and privacy risk in production environments. [security]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Keycloak OAuth logins leak PII into app logs.
   - ⚠️ Centralized logging stores emails and profile attributes.
   - ⚠️ Harder to meet privacy and compliance requirements.
   ```
   </details>
   
   ```suggestion
   log.debug("Received userinfo from OIDC provider for user %s", me.get("preferred_username"))
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Deploy Superset on Kubernetes with the Keycloak `enable_oauth` example from
   `docs/docs/installation/kubernetes.mdx` copied verbatim into
   `configOverrides.enable_oauth`, including the `log.info(f'userinfo: {me}')` line at
   approximately line 408.
   
   2. Configure logging for the Superset webserver to use the default INFO log level (the
   standard production setting for many deployments).
   
   3. Have any user authenticate via the configured Keycloak OAuth provider (`provider` name
   `keycloak` as defined in `OAUTH_PROVIDERS` in the same config block). During login,
   Superset calls `CustomSsoSecurityManager.get_oauth_user_info('keycloak', response)` which
   issues the userinfo request and assigns `me = resp.json()`.
   
   4. The line `log.info(f'userinfo: {me}')` at `docs/docs/installation/kubernetes.mdx:408`
   logs the full `userinfo` JSON including email, full name, username, and groups to the
   application logs on every login, making this PII available to anyone with access to logs
   and potentially to log aggregation systems.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/docs/installation/kubernetes.mdx
   **Line:** 408:408
   **Comment:**
   	*Security: Logging the entire `userinfo` payload at info level will store personally identifiable information (like emails and full profile data) in standard logs, which is a security and privacy risk in production environments.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=a05101bd0c458359bba7ea29d786591843ff106325df28fa0c4da01cbcbeca97&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=a05101bd0c458359bba7ea29d786591843ff106325df28fa0c4da01cbcbeca97&reaction=dislike'>👎</a>



##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,122 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+Clients -> <your-client-id> -> Advanced -> Advanced settings
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+    import requests
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = 'Public'
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    # Custom OAuth view to handle logout redirection to Keycloak
+    class CustomOAuthView(AuthOAuthView):
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+
+
+    class CustomSsoSecurityManager(SupersetSecurityManager):
+        # Override the default OAuth view with our custom one
+        authoauthview = CustomOAuthView
+
+        # Override the method to fetch groups from the token and map them to Superset roles
+        def get_oauth_user_info(self, provider, response):
+            if provider == 'keycloak':
+                headers = {'Authorization': f"Bearer {response['access_token']}"}
+                resp = requests.get(OIDC_USERINFO_URL, headers=headers)
+                me = resp.json()

Review Comment:
   **Suggestion:** The call to the OIDC userinfo endpoint uses `requests.get` without a timeout, so if the identity provider is slow or unresponsive, login requests can hang indefinitely and tie up worker processes. [possible bug]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Keycloak-based logins can hang during IdP outages.
   - ⚠️ Webserver workers may be exhausted under partial outages.
   - ⚠️ User authentication reliability reduced during network issues.
   ```
   </details>
   
   ```suggestion
                   resp = requests.get(OIDC_USERINFO_URL, headers=headers, timeout=5)
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Deploy Superset using the Kubernetes Helm chart and copy the Keycloak OAuth example
   from `docs/docs/installation/kubernetes.mdx` into `configOverrides.enable_oauth`,
   including the `requests.get(OIDC_USERINFO_URL, headers=headers)` call in
   `CustomSsoSecurityManager.get_oauth_user_info` (around line 405).
   
   2. Configure the `CLIENT_ID`, `CLIENT_SECRET`, and `OIDC_ISSUER` environment variables as
   described in the same example so that `OIDC_USERINFO_URL` points at your IdP (e.g.,
   Keycloak `.../protocol/openid-connect/userinfo`).
   
   3. Simulate an IdP/network issue by making the OIDC userinfo endpoint slow or unresponsive
   (for example, by adding a firewall rule that drops packets to the userinfo URL, or by
   stopping the Keycloak instance while keeping DNS/resolution unchanged).
   
   4. Have a user attempt to log in via the Keycloak OAuth provider. The Superset webserver
   calls `requests.get(OIDC_USERINFO_URL, headers=headers)` at
   `docs/docs/installation/kubernetes.mdx:405` with no timeout, causing the request (and
   therefore the login HTTP request) to hang until the underlying HTTP stack or webserver
   kills the worker, tying up resources and degrading availability.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/docs/installation/kubernetes.mdx
   **Line:** 405:405
   **Comment:**
   	*Possible Bug: The call to the OIDC userinfo endpoint uses `requests.get` without a timeout, so if the identity provider is slow or unresponsive, login requests can hang indefinitely and tie up worker processes.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=f26999d3e2048e7b35e6b8b097e2abc127a752993c889c4086d8ecad89d15bf0&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=f26999d3e2048e7b35e6b8b097e2abc127a752993c889c4086d8ecad89d15bf0&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "rusackas (via GitHub)" <gi...@apache.org>.
rusackas commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2879858718


##########
docs/admin_docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,161 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+`Clients -> your-client-id -> Advanced -> Advanced settings`
+
+This code correctly handles the case where a user successfully authenticates with Keycloak but does not belong to any of the mapped groups.
+
+In that situation, the user is simply redirected back to the login page.
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    class CustomOAuthView(AuthOAuthView):
+        # Override the logout method to also log out from the OIDC provider
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+

Review Comment:
   Curious what you think of this feedback. 
   
   I'm also not sure about a more meta-question here: how deep we want to get into code examples in the docs? It's walking a fine line between something that should be documented here in the docs and something that could be contributed as an actual code file / implementation example, if I'm understanding correctly. 
   
   But then... if we have multiple implementation examples in the code, I'm not sure what can be abstracted away as configuration vs logic... I wouldn't want to maintain "dead code" for the sake of one possible example. 
   
   Maybe @villebro or @michael-s-molina have some ideas here... maybe I'm overthinking all this and should just stamp it, especially if it closes two issues :D My concern is only to find the way forward with the least maintenance overhead.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r3455967092


##########
docs/admin_docs/security/oauth.mdx:
##########
@@ -0,0 +1,183 @@
+---
+title: OAuth Configuration
+sidebar_position: 4
+---
+
+# Keycloak
+
+## Complete example: Keycloak with PKCE and group mapping
+
+This example demonstrates a complete Keycloak integration with Superset, including group-to-role mapping, single logout with Keycloak, and PKCE support.
+
+First, create a Secret containing the following values:
+
+* `CLIENT_ID`
+* `CLIENT_SECRET`
+* `OIDC_ISSUER`
+
+The Keycloak client must be configured to support the PKCE flow.
+
+To enable PKCE, set **Proof Key for Code Exchange Code Challenge Method** to **S256** under:
+
+`Clients -> my_superset_clientid -> Advanced -> Advanced settings`
+
+This implementation correctly handles the case where a user successfully authenticates with Keycloak but does not belong to any of the configured groups.
+
+The following snippet defines the mapping between Keycloak groups and Superset roles:
+
+```python
+AUTH_ROLES_MAPPING = {
+    f'{CLIENT_ID}_admin': ['Admin'],
+    f'{CLIENT_ID}_alpha': ['Alpha'],
+    f'{CLIENT_ID}_gamma': ['Gamma'],
+    f'{CLIENT_ID}_public': ['Public'],
+}
+```
+
+If a user does not belong to any of the mapped groups, they will be redirected back to the login page.
+
+Make sure the following groups exist in Keycloak and that users are assigned to at least one of them:
+
+* `<my_superset_clientid>_admin`
+* `<my_superset_clientid>_alpha`
+* `<my_superset_clientid>_gamma`
+* `<my_superset_clientid>_public`
+
+## Helm chart configuration
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://mykeycloak.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    class CustomOAuthView(AuthOAuthView):
+        # Override the logout method to also log out from the OIDC provider
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            super().logout()
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'

Review Comment:
   <div>
   
   
   <div id="suggestion">
   <div id="issue"><b>CWE-20: Unencoded logout redirect URI</b></div>
   <div id="fix">
   
   The `post_logout_redirect_uri` parameter value is not URL-encoded. `request.url_root.strip('/')` may contain special characters (e.g., port, path) that require encoding per OIDC spec. Use `quote(request.url_root.strip('/'), safe='')` or construct query params via urlencode. (See also: [CWE-20](https://cwe.mitre.org/data/definitions/20.html))
   </div>
   
   
   <details>
   <summary>
   <b>Code suggestion</b>
   </summary>
   <blockquote>Check the AI-generated fix before applying</blockquote>
   <div id="code">
   
   
   ```
    --- docs/admin_docs/security/oauth.mdx
    +++ docs/admin_docs/security/oauth.mdx
    @@ -114,7 +114,8 @@
             def logout(self):
                 super().logout()
                 session.clear()
    -            return redirect(
    -                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
    +            from urllib.parse import quote
    +            return redirect(
    +                f"{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={quote(request.url_root.strip('/'), safe='')}&client_id={CLIENT_ID}"
                 )
   ```
   
   </div>
   </details>
   
   
   
   </div>
   
   
   
   
   <small><i>Code Review Run #cffcdd</i></small>
   </div>
   
   ---
   Should Bito avoid suggestions like this for future reviews? (<a href=https://alpha.bito.ai/home/ai-agents/review-rules>Manage Rules</a>)
   - [ ] Yes, avoid them



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4773854803

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-6315359956

   ## CodeAnt PR Risk: Medium Risk
   
   - The PR needs attention before merging.
   - The documented PKCE setting remains under client_kwargs, where it may be ignored, leaving the example's OAuth flow without the promised PKCE protection.
   - Userinfo and provisioning failures in the OAuth callback are uncaught and can return server errors instead of a controlled login failure.
   - The logout redirect derives its destination from request.url_root, which can point to an internal host behind some proxies and be rejected by Keycloak.
   
   **Assessed commit:** `9c4eda85ee15`


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4015907892

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4046879687

   ## **Sequence Diagram**
   
   This PR adds documentation for a complete Keycloak OAuth setup in Superset, covering PKCE login, group to role mapping, and logout behavior. The flow highlights that users are only logged in when at least one mapped group is present, and logout clears Superset session before redirecting to provider logout.
   
   ```mermaid
   sequenceDiagram
       participant User
       participant Superset
       participant Keycloak
   
       User->>Superset: Start OAuth login
       Superset->>Keycloak: Redirect for PKCE authorization
       Keycloak-->>Superset: Return authorization code
       Superset->>Keycloak: Exchange code and fetch user info
       Keycloak-->>Superset: Return profile and groups
   
       alt Has mapped groups
           Superset->>Superset: Sync roles and create session
           Superset-->>User: Redirect to app home
       else No mapped groups
           Superset-->>User: Redirect to login page
       end
   
       User->>Superset: Request logout
       Superset->>Superset: Clear local session
       Superset-->>User: Redirect to provider logout and return uri
   ```
   
   ---
   *Generated by [CodeAnt AI](https://codeant.ai)*
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "albundy83 (via GitHub)" <gi...@apache.org>.
albundy83 commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-6315692552

   Here a new proposal :)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4933525428

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "rusackas (via GitHub)" <gi...@apache.org>.
rusackas commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4910133052

   Thanks @albundy83, this is a useful page... we don't have a good Keycloak example, and PKCE plus group mapping is exactly what people ask about. Couple of accuracy things worth fixing so folks don't hit a wall following it:
   
   The `OIDC_ISSUER` still has `/auth` in the path, which Keycloak dropped in 17+... on any current Keycloak that URL 404s the discovery metadata. Worth switching to `.../realms/MYREALM` with a note that older versions need the `/auth` prefix.
   
   And the group mapping: Keycloak doesn't emit a `groups` claim by default, and once you add the mapper it comes back as a full path with a leading slash (`/my_group`) unless you turn that off. As written, `groups = data.get('groups', [])` would come back empty and the user gets no roles... which is the thing the page is trying to solve. A sentence on adding the Group Membership mapper (full path off) or stripping the leading `/` would close that gap.
   
   Happy to stamp it once those are in. Thanks!


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3982718599

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "netlify[bot] (via GitHub)" <gi...@apache.org>.
netlify[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3935731411

   ### <span aria-hidden="true">✅</span> Deploy Preview for *superset-docs-preview* ready!
   
   
   |  Name | Link |
   |:-:|------------------------|
   |<span aria-hidden="true">🔨</span> Latest commit | 425776b9db9c75c2c55228d43d93c374e240c070 |
   |<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/projects/superset-docs-preview/deploys/699883eec1b37800081f576c |
   |<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-38092--superset-docs-preview.netlify.app](https://deploy-preview-38092--superset-docs-preview.netlify.app) |
   |<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTM4MDkyLS1zdXBlcnNldC1kb2NzLXByZXZpZXcubmV0bGlmeS5hcHAifQ.zfDAZOdy55PpNVcn1amhdMiywCQDK7m6O-48Kj2ElEM)<br /><br />_Use your smartphone camera to open QR code link._</details> |
   ---
   <!-- [superset-docs-preview Preview](https://deploy-preview-38092--superset-docs-preview.netlify.app) -->
   _To edit notification comments on pull requests, go to your [Netlify project configuration](https://app.netlify.com/projects/superset-docs-preview/configuration/notifications#deploy-notifications)._


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "rusackas (via GitHub)" <gi...@apache.org>.
rusackas commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4015079666

   Raising some concerns from a quick (AI assisted) review:
   
     1. Wrong file — This is landing in kubernetes.mdx, but the content is generic OAuth
     config that applies to any deployment. It deserves its own page or a spot in the
     auth/security docs, not buried mid-Kubernetes-install-guide.
     
     2. Very Keycloak-specific — The URL structure (/protocol/openid-connect/...), the
     `:::note` framing, and even the group key names are all Keycloak-specific. If it stays,
     it should be clearly scoped as a "Keycloak example" rather than a general OAuth guide
     improvement.
     
     3. `:::note` is the wrong container — The admonition wraps setup instructions, not a
     note. It'd be cleaner as a `:::tip` with a header like "Full example: Keycloak with PKCE
     and group mapping" or just as a regular `##` section.
     
     4. PR title — feat: Improve oauth doc should be docs(auth): add Keycloak PKCE and
     group-mapping example or similar.
     
     5. `get_url_for_index` missing `()` — Used in several redirect calls as
     `self.appbuilder.get_url_for_index` without calling it. If it's a method (not a
     property), those redirects would go to the function object, not the URL. Worth
     double-checking.
     
     Lemme know what you think :)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "albundy83 (via GitHub)" <gi...@apache.org>.
albundy83 commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2883790435


##########
docs/admin_docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,161 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+`Clients -> your-client-id -> Advanced -> Advanced settings`
+
+This code correctly handles the case where a user successfully authenticates with Keycloak but does not belong to any of the mapped groups.
+
+In that situation, the user is simply redirected back to the login page.
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    class CustomOAuthView(AuthOAuthView):
+        # Override the logout method to also log out from the OIDC provider
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+

Review Comment:
   The feedback is ok, I have changed it like this:
   ```python
       class CustomOAuthView(AuthOAuthView):
           # Override the logout method to also log out from the OIDC provider
           @expose('/logout/', methods=['GET', 'POST'])
           def logout(self):
               super().logout()
               session.clear()
               return redirect(
                   f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
               )
   ```
   I understand your point about a so complete example.
   
   But, it was not easy to find a code that works and handle some classical cases:
   - be a part of a group to be able to connect to superset (and of course map it inside superset)
   - but also if you are able to connect to SSO but does not belong to a group, you have a correct page not an error
   - a proper logout
   
   There were also many examples that are old or not ok anymore with new versions.
   
   That's why I made this pull request :)
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r3453876127


##########
docs/admin_docs/security/oauth.mdx:
##########
@@ -0,0 +1,182 @@
+---
+title: Oauth examples
+sidebar_position: 4
+---
+
+# Keycloak with PKCE, clean logout and groups mapping
+
+Here a full example using Keycloak as an OIDC provider with PKCE flow, clean logout and groups mapping to Superset roles.
+
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Keycloak must be configured to support PKCE flow, so you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+`Clients -> your-client-id -> Advanced -> Advanced settings`
+
+Logout is first handled by Superset to clear the session and then the user is redirected to Keycloak logout endpoint to complete the logout process on the OIDC provider side.
+It is important to clear the session in Superset first to avoid any issues with the OIDC provider.
+
+This code correctly handles the case where a user successfully authenticates with Keycloak but does not belong to any of the mapped groups.
+In that situation, the user is simply redirected back to the login page.
+
+## The Secret
+You can create the Secret with a manifest like this:
+```yaml
+apiVersion: v1
+kind: Secret
+metadata:
+  name: superset-oauth-providers
+  namespace: my-beloved-superset-namespace
+stringData:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+type: Opaque
+```
+
+and you will need to reference it in your Helm values like this:
+```yaml
+envFromSecrets:
+  - superset-oauth-providers
+```
+
+Or you can directly set the environment variables in the values file like this:
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+```
+
+## The config overrides
+```yaml
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    class CustomOAuthView(AuthOAuthView):
+        # Override the logout method to also log out from the OIDC provider
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            super().logout()
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'

Review Comment:
   **Suggestion:** Building `post_logout_redirect_uri` from `request.url_root` makes logout depend on the incoming Host/proxy headers, which often resolves to an internal URL behind ingress and causes Keycloak to reject logout with an invalid redirect URI. Use a fixed externally configured base URL (and URL-encode it) instead of deriving it from each request. [security]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Keycloak logout fails due to invalid redirect URI.
   - ⚠️ Logout brittle behind load balancer or proxy setups.
   - ⚠️ Documentation promotes host-derived logout redirect pattern.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Copy the documented `configOverrides.enable_oauth` snippet from
   `docs/admin_docs/security/oauth.mdx:50-182` into your Helm values so it is rendered into
   the running Superset container as configuration (per the Helm `configOverrides` mechanism
   described in this doc).
   
   2. Deploy Superset with this configuration so that initialization in
   `superset/initialization/__init__.py:940-949` reads `CUSTOM_SECURITY_MANAGER =
   CustomSsoSecurityManager` from config (as set at
   `docs/admin_docs/security/oauth.mdx:180-181`) and assigns `CustomSsoSecurityManager` as
   `appbuilder.security_manager_class`, which in turn uses `CustomOAuthView` defined at
   `docs/admin_docs/security/oauth.mdx:110-118` as the OAuth auth view.
   
   3. Log in to Superset via Keycloak, then trigger logout by requesting `/logout/` in the
   browser; Flask-AppBuilder routes this to `CustomOAuthView.logout()` at
   `docs/admin_docs/security/oauth.mdx:112-118`, which calls
   `redirect(f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}')`.
   
   4. Run Superset behind a reverse proxy/ingress where the external URL registered in
   Keycloak is `https://superset.example.com/` but the WSGI request `url_root` resolves to an
   internal host like `http://superset.superset.svc.cluster.local/` (a common Kubernetes
   pattern). On logout, observe Keycloak rejecting the request with an "invalid redirect URI"
   or similar error because `post_logout_redirect_uri` is built from `request.url_root`
   (internal host) instead of a fixed, registered external URL, causing the provider logout
   to fail.
   ```
   </details>
   
   [![Fix in Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=7e7c39686c334b23bf9b0a80db1f04f2&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [![Fix in VSCode Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=7e7c39686c334b23bf9b0a80db1f04f2&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/admin_docs/security/oauth.mdx
   **Line:** 117:117
   **Comment:**
   	*Security: Building `post_logout_redirect_uri` from `request.url_root` makes logout depend on the incoming Host/proxy headers, which often resolves to an internal URL behind ingress and causes Keycloak to reject logout with an invalid redirect URI. Use a fixed externally configured base URL (and URL-encode it) instead of deriving it from each request.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=7f7a3c9fb27f1b9644b7f184884a5a2ac50d03d5b5a9ed02ba89150d1776361e&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=7f7a3c9fb27f1b9644b7f184884a5a2ac50d03d5b5a9ed02ba89150d1776361e&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "albundy83 (via GitHub)" <gi...@apache.org>.
albundy83 commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4770635905

   Hello, sure, what about a `docs/admin_docs/security/oauth.mdx` dedicated file ?
   And maybe a small ref in kubernetes file, something like:
   ```
   More complete examples of OAuth configuration can be found in the [Security documentation](/admin-docs/security/oauth.mdx).
   ``
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r3454031077


##########
docs/admin_docs/installation/kubernetes.mdx:
##########
@@ -262,6 +262,7 @@ OAuth setup requires that the [authlib](https://authlib.org/) Python library is
 be done using `pip` by updating the `bootstrapScript`. See the [Dependencies](#dependencies) section
 for more information.
 
+More complete examples of OAuth configuration can be found in the [Security documentation](/admin-docs/security/ouath.mdx).

Review Comment:
   **Suggestion:** The documentation link points to `/admin-docs/security/ouath.mdx`, but the new page is `oauth.mdx`. This typo creates a broken link (404) and prevents readers from reaching the OAuth setup guide; update the target path to the correct OAuth page URL. [code quality]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Kubernetes OAuth docs link returns 404 for readers.
   - ⚠️ Users miss detailed OAuth and Keycloak configuration docs.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Open the Kubernetes installation docs at `docs/admin_docs/installation/kubernetes.mdx`
   and navigate to the section around line 265 containing the sentence: `More complete
   examples of OAuth configuration can be found in the [Security
   documentation](/admin-docs/security/ouath.mdx).`
   
   2. Note that the rendered link target is `/admin-docs/security/ouath.mdx` as specified in
   that markdown link at line 265.
   
   3. Inspect the security docs directory at `docs/admin_docs/security` (see LS results),
   which contains `oauth.md` but no file named `ouath.*` or `ouath.mdx`, confirming that the
   `ouath` path does not map to any existing page.
   
   4. Build or browse the documentation site and click the "Security documentation" link from
   the Kubernetes page; observe that the browser is sent to `/admin-docs/security/ouath.mdx`
   and receives a 404/Not Found instead of loading the existing OAuth documentation defined
   in `docs/admin_docs/security/oauth.md`.
   ```
   </details>
   
   [![Fix in Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=e3f2a8d63f6549a9a19a0fccf64ed13a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [![Fix in VSCode Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=e3f2a8d63f6549a9a19a0fccf64ed13a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/admin_docs/installation/kubernetes.mdx
   **Line:** 265:265
   **Comment:**
   	*Code Quality: The documentation link points to `/admin-docs/security/ouath.mdx`, but the new page is `oauth.mdx`. This typo creates a broken link (404) and prevents readers from reaching the OAuth setup guide; update the target path to the correct OAuth page URL.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=d301c600cd55b5862c36957db7ca5042ca2d005338902328721c5dc61feaba0d&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=d301c600cd55b5862c36957db7ca5042ca2d005338902328721c5dc61feaba0d&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r3454959446


##########
docs/admin_docs/installation/kubernetes.mdx:
##########
@@ -262,6 +262,7 @@ OAuth setup requires that the [authlib](https://authlib.org/) Python library is
 be done using `pip` by updating the `bootstrapScript`. See the [Dependencies](#dependencies) section
 for more information.
 
+More complete examples of OAuth configuration can be found in the [Security documentation](/admin-docs/security/oauth.mdx).

Review Comment:
   <div>
   
   
   <div id="suggestion">
   <div id="issue"><b>Inconsistent link format</b></div>
   <div id="fix">
   
   The link includes `.mdx` extension but all other security documentation links omit it (e.g., `/admin-docs/security/securing_superset`, `/admin-docs/security/`). Remove the extension for consistency with the established documentation pattern.
   </div>
   
   
   <details>
   <summary>
   <b>Code suggestion</b>
   </summary>
   <blockquote>Check the AI-generated fix before applying</blockquote>
   <div id="code">
   
   
   ```
    --- docs/admin_docs/installation/kubernetes.mdx
    +++ docs/admin_docs/installation/kubernetes.mdx
    @@ -262,6 +262,6 @@
     for more information.
    
    -More complete examples of OAuth configuration can be found in the [Security documentation](/admin-docs/security/oauth.mdx).
    +More complete examples of OAuth configuration can be found in the [Security documentation](/admin-docs/security/oauth).
     :::
   ```
   
   </div>
   </details>
   
   
   
   </div>
   
   
   
   
   <small><i>Code Review Run #8b6302</i></small>
   </div>
   
   ---
   Should Bito avoid suggestions like this for future reviews? (<a href=https://alpha.bito.ai/home/ai-agents/review-rules>Manage Rules</a>)
   - [ ] Yes, avoid them



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3936438308

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3935176690

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3986250269

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r3671440421


##########
docs/admin_docs/security/oauth.mdx:
##########
@@ -0,0 +1,269 @@
+---
+title: OAuth Configuration
+sidebar_position: 4
+---
+
+# Keycloak
+
+## Complete example: Keycloak with PKCE and group mapping
+
+This example demonstrates a complete Keycloak integration with Superset, including:
+
+* **PKCE** (Proof Key for Code Exchange) on top of a confidential client
+* **Group-to-role mapping**: Keycloak groups are mapped to Superset roles at every login (`AUTH_ROLES_SYNC_AT_LOGIN`)
+* **Access control**: users who authenticate successfully but do not belong to any mapped group are rejected with an explicit message instead of being silently logged in
+* **Single logout** (RP-Initiated Logout): logging out of Superset also terminates the Keycloak SSO session, using `id_token_hint`
+
+## Prerequisites: Keycloak client configuration
+
+### 1. Client settings
+
+Create a confidential OIDC client (e.g. `my_superset_clientid`) with:
+
+* **Valid redirect URIs**: `https://<superset-host>/oauth-authorized/keycloak`
+* **Valid post logout redirect URIs**: `https://<superset-host>` — required for the single-logout redirect to be accepted by Keycloak
+
+### 2. Enable PKCE
+
+Set **Proof Key for Code Exchange Code Challenge Method** to **S256** under:
+
+`Clients -> my_superset_clientid -> Advanced -> Advanced settings`
+
+### 3. Expose group membership in the userinfo response
+
+:::warning
+Keycloak does **not** expose a `groups` claim by default. Without this mapper, every user will be rejected with "no valid groups" even if they are correctly assigned in Keycloak.
+:::
+
+Add a **Group Membership** mapper to the client:
+
+`Clients -> my_superset_clientid -> Client scopes -> my_superset_clientid-dedicated -> Add mapper -> By configuration -> Group Membership`
+
+* **Token Claim Name**: `groups`
+* **Full group path**: **OFF** — otherwise groups are returned as `/my_superset_clientid_admin` (with a leading slash) and the role mapping will silently fail
+* **Add to userinfo**: **ON**
+
+### 4. Create the groups
+
+Make sure the following groups exist in Keycloak and that users are assigned to at least one of them:
+
+* `<my_superset_clientid>_admin`
+* `<my_superset_clientid>_alpha`
+* `<my_superset_clientid>_gamma`
+* `<my_superset_clientid>_public`
+
+The mapping between Keycloak groups and Superset roles is defined by `AUTH_ROLES_MAPPING` in the configuration below. Users who do not belong to any of the mapped groups are shown an explicit access-denied page, without being logged in.
+
+:::note
+This example deliberately renders the access-denied page directly from the OAuth callback instead of using Flask `flash()` messages. Starting with the React-based login page (Superset 6.x lineage), flash messages are no longer displayed anywhere in the UI, so a `flash()` + redirect would fail silently and the user would bounce between Superset and Keycloak (whose SSO session is still active) with no explanation. A directly rendered response works on every Superset version. The `AuthOAuthView` subclassing pattern itself still works on 6.x because the `/oauth-authorized/<provider>` callback route is still served by Flask-AppBuilder — but verify against your target version, as login-flow extension points are being reworked.
+:::
+
+:::note
+The issuer URL format depends on your Keycloak version. Legacy (Wildfly-based, < 17) distributions use `https://<keycloak-host>/auth/realms/<REALM>`, while modern (Quarkus-based) distributions use `https://<keycloak-host>/realms/<REALM>` — without the `/auth` prefix.
+:::
+
+## Kubernetes Secret
+
+Create a Secret containing the OIDC credentials, so they never appear in your Helm values (and therefore never end up in Git):
+
+```bash
+kubectl create secret generic superset-oidc \
+  --namespace superset \
+  --from-literal=CLIENT_ID='my_superset_clientid' \
+  --from-literal=CLIENT_SECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
+  --from-literal=OIDC_ISSUER='https://mykeycloak.youpi.fr/realms/MYREALM'
+```
+
+In a GitOps workflow, prefer provisioning this Secret through your secret management tooling (e.g. External Secrets Operator, Sealed Secrets) rather than creating it imperatively.
+
+## Helm chart configuration
+
+Reference the Secret with `envFromSecret` instead of putting values in `extraSecretEnv`:
+
+```yaml
+envFromSecret: superset-oidc

Review Comment:
   **Suggestion:** Setting `envFromSecret` replaces the chart's default environment Secret rather than adding another Secret. The documented `superset-oidc` Secret contains only OIDC variables, so the generated `DB_*` and `REDIS_*` variables are no longer injected into the pods, causing the Superset web, worker, and initialization containers to fail when they attempt to connect to the database or cache. Use `envFromSecrets` for the additional OIDC Secret, or include all required chart environment keys in the referenced Secret. [api mismatch]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Helm initialization cannot locate database settings.
   - ❌ Web and worker pods lose database connectivity.
   - ❌ Celery components lose Redis connection settings.
   - ⚠️ Documented Keycloak deployment fails before OAuth login.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Create the documented `superset-oidc` Secret from
   `docs/admin_docs/security/oauth.mdx:65-75`; it contains only `CLIENT_ID`, `CLIENT_SECRET`,
   and `OIDC_ISSUER`.
   
   2. Deploy the chart with `envFromSecret: superset-oidc` as documented at
   `docs/admin_docs/security/oauth.mdx:81-84`.
   
   3. The chart injects only the selected Secret through
   `helm/superset/templates/deployment.yaml:120-125`,
   `helm/superset/templates/deployment-worker.yaml:114-119`, and
   `helm/superset/templates/init-job.yaml:88-93`; the default environment Secret is no longer
   referenced.
   
   4. The chart-generated default Secret normally supplies `DB_HOST`, `DB_PORT`, `DB_USER`,
   `DB_PASS`, `DB_NAME`, and Redis variables in
   `helm/superset/templates/secret-env.yaml:21-35`. The init container then reads `DB_HOST`
   and `DB_PORT` at `helm/superset/values.yaml:445-450`, while other startup checks read
   database and Redis variables at `helm/superset/values.yaml:582-583`.
   
   5. Observe that initialization and the web or worker pods fail or cannot connect because
   the OIDC-only Secret does not provide the required database and Redis environment
   variables. Configure `envFromSecrets: [superset-oidc]` instead, or include the chart
   environment keys in the referenced Secret.
   ```
   </details>
   
   [![Fix in Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=de1093b5a68b49d3a3b952c7868f7dd7&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [![Fix in VSCode Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=de1093b5a68b49d3a3b952c7868f7dd7&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/admin_docs/security/oauth.mdx
   **Line:** 84:84
   **Comment:**
   	*Api Mismatch: Setting `envFromSecret` replaces the chart's default environment Secret rather than adding another Secret. The documented `superset-oidc` Secret contains only OIDC variables, so the generated `DB_*` and `REDIS_*` variables are no longer injected into the pods, causing the Superset web, worker, and initialization containers to fail when they attempt to connect to the database or cache. Use `envFromSecrets` for the additional OIDC Secret, or include all required chart environment keys in the referenced Secret.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=e7c22e396da9b828d5f16dc4f501660b0d0f778850b66e27a61d5a97c1695baa&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=e7c22e396da9b828d5f16dc4f501660b0d0f778850b66e27a61d5a97c1695baa&reaction=dislike'>👎</a>



##########
docs/admin_docs/security/oauth.mdx:
##########
@@ -0,0 +1,269 @@
+---
+title: OAuth Configuration
+sidebar_position: 4
+---
+
+# Keycloak
+
+## Complete example: Keycloak with PKCE and group mapping
+
+This example demonstrates a complete Keycloak integration with Superset, including:
+
+* **PKCE** (Proof Key for Code Exchange) on top of a confidential client
+* **Group-to-role mapping**: Keycloak groups are mapped to Superset roles at every login (`AUTH_ROLES_SYNC_AT_LOGIN`)
+* **Access control**: users who authenticate successfully but do not belong to any mapped group are rejected with an explicit message instead of being silently logged in
+* **Single logout** (RP-Initiated Logout): logging out of Superset also terminates the Keycloak SSO session, using `id_token_hint`
+
+## Prerequisites: Keycloak client configuration
+
+### 1. Client settings
+
+Create a confidential OIDC client (e.g. `my_superset_clientid`) with:
+
+* **Valid redirect URIs**: `https://<superset-host>/oauth-authorized/keycloak`
+* **Valid post logout redirect URIs**: `https://<superset-host>` — required for the single-logout redirect to be accepted by Keycloak
+
+### 2. Enable PKCE
+
+Set **Proof Key for Code Exchange Code Challenge Method** to **S256** under:
+
+`Clients -> my_superset_clientid -> Advanced -> Advanced settings`
+
+### 3. Expose group membership in the userinfo response
+
+:::warning
+Keycloak does **not** expose a `groups` claim by default. Without this mapper, every user will be rejected with "no valid groups" even if they are correctly assigned in Keycloak.
+:::
+
+Add a **Group Membership** mapper to the client:
+
+`Clients -> my_superset_clientid -> Client scopes -> my_superset_clientid-dedicated -> Add mapper -> By configuration -> Group Membership`
+
+* **Token Claim Name**: `groups`
+* **Full group path**: **OFF** — otherwise groups are returned as `/my_superset_clientid_admin` (with a leading slash) and the role mapping will silently fail
+* **Add to userinfo**: **ON**
+
+### 4. Create the groups
+
+Make sure the following groups exist in Keycloak and that users are assigned to at least one of them:
+
+* `<my_superset_clientid>_admin`
+* `<my_superset_clientid>_alpha`
+* `<my_superset_clientid>_gamma`
+* `<my_superset_clientid>_public`
+
+The mapping between Keycloak groups and Superset roles is defined by `AUTH_ROLES_MAPPING` in the configuration below. Users who do not belong to any of the mapped groups are shown an explicit access-denied page, without being logged in.
+
+:::note
+This example deliberately renders the access-denied page directly from the OAuth callback instead of using Flask `flash()` messages. Starting with the React-based login page (Superset 6.x lineage), flash messages are no longer displayed anywhere in the UI, so a `flash()` + redirect would fail silently and the user would bounce between Superset and Keycloak (whose SSO session is still active) with no explanation. A directly rendered response works on every Superset version. The `AuthOAuthView` subclassing pattern itself still works on 6.x because the `/oauth-authorized/<provider>` callback route is still served by Flask-AppBuilder — but verify against your target version, as login-flow extension points are being reworked.
+:::
+
+:::note
+The issuer URL format depends on your Keycloak version. Legacy (Wildfly-based, < 17) distributions use `https://<keycloak-host>/auth/realms/<REALM>`, while modern (Quarkus-based) distributions use `https://<keycloak-host>/realms/<REALM>` — without the `/auth` prefix.
+:::
+
+## Kubernetes Secret
+
+Create a Secret containing the OIDC credentials, so they never appear in your Helm values (and therefore never end up in Git):
+
+```bash
+kubectl create secret generic superset-oidc \
+  --namespace superset \
+  --from-literal=CLIENT_ID='my_superset_clientid' \
+  --from-literal=CLIENT_SECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
+  --from-literal=OIDC_ISSUER='https://mykeycloak.youpi.fr/realms/MYREALM'
+```
+
+In a GitOps workflow, prefer provisioning this Secret through your secret management tooling (e.g. External Secrets Operator, Sealed Secrets) rather than creating it imperatively.
+
+## Helm chart configuration
+
+Reference the Secret with `envFromSecret` instead of putting values in `extraSecretEnv`:
+
+```yaml
+envFromSecret: superset-oidc
+
+configOverrides:
+  enable_proxy_fix: |
+    # Required when Superset runs behind an ingress / reverse proxy terminating TLS.
+    # Without it, redirect_uri and the post-logout redirect are generated with
+    # http:// and Keycloak rejects the callback.
+    ENABLE_PROXY_FIX = True
+
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OIDC_LOGOUT_URL = f'{OIDC_BASE_URL}/logout'
+
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Keycloak group -> Superset role mapping.
+    # Make sure these groups exist in Keycloak (see Prerequisites).
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    def access_denied_response(message, login_url):
+        # Rendered directly instead of flash(): the React-based login page
+        # (Superset 6.x) does not display Flask flash messages, so a
+        # flash + redirect fails silently. This works on every version.
+        return (
+            '<html><body style="font-family: sans-serif; text-align: center; margin-top: 10%">'
+            '<h2>Access denied</h2>'
+            f'<p>{message}</p>'
+            f'<p>Contact your administrator, then <a href="{login_url}">try again</a>.</p>'
+            '</body></html>',
+            403,
+        )
+
+
+    class CustomOAuthView(AuthOAuthView):
+        # Override the logout method to also terminate the Keycloak SSO session
+        # (OIDC RP-Initiated Logout). The id_token stored at login time is passed
+        # as id_token_hint so Keycloak can identify the session without prompting.
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            id_token = session.get('oidc_id_token')
+            super().logout()
+            session.clear()
+            post_logout_redirect_uri = request.url_root.strip('/')
+            logout_url = (
+                f'{OIDC_LOGOUT_URL}'
+                f'?post_logout_redirect_uri={post_logout_redirect_uri}'
+                f'&client_id={CLIENT_ID}'
+            )
+            if id_token:
+                logout_url += f'&id_token_hint={id_token}'
+            return redirect(logout_url)
+
+        # Override the authorized method to handle the OIDC callback and map groups to roles
+        @expose('/oauth-authorized/<provider>')
+        def oauth_authorized(self, provider):
+            # Step 1: exchange the authorization code for an access token
+            try:
+                resp = self.appbuilder.sm.oauth_remotes[provider].authorize_access_token()
+            except Exception as e:
+                log.exception(f'Error fetching access token: {e}')
+                return redirect(self.appbuilder.get_url_for_index)
+
+            # Step 2: fetch user info from the OIDC provider
+            userinfo = self.appbuilder.sm.get_oauth_user_info(provider, resp)
+            role_keys = userinfo.get('role_keys', [])
+            known_groups = [g for g in role_keys if g in AUTH_ROLES_MAPPING]

Review Comment:
   **Suggestion:** The custom callback only handles exceptions from `authorize_access_token()`. Failures from the userinfo request, HTTP status validation, JSON parsing, or user provisioning in the following code are uncaught and produce a server error instead of the controlled OAuth failure response described by this example. Wrap the entire callback processing flow in the error handling path or explicitly handle these failures. [possible bug]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Keycloak outages produce OAuth callback 500 errors.
   - ❌ Malformed userinfo responses bypass access-denied handling.
   - ⚠️ Users receive server errors instead of login recovery.
   - ⚠️ Provisioning failures expose an uncontrolled authentication path.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure the documented Keycloak provider, then begin the real OAuth flow through the
   Flask-AppBuilder callback route `/oauth-authorized/keycloak` defined at
   `docs/admin_docs/security/oauth.mdx:186-188`.
   
   2. Complete authorization successfully so `authorize_access_token()` returns at
   `docs/admin_docs/security/oauth.mdx:191`, allowing execution to leave the try block at
   lines 190-194.
   
   3. Make the subsequent Keycloak userinfo request fail, return a non-success status, or
   return invalid JSON. The custom security manager performs that request at
   `docs/admin_docs/security/oauth.mdx:236-240`, calls `raise_for_status()` at line 239, and
   calls `json()` at line 240 without handling exceptions.
   
   4. The callback invokes `get_oauth_user_info()` at
   `docs/admin_docs/security/oauth.mdx:197`; exceptions from the userinfo request or parsing
   therefore propagate past the only callback handler instead of producing the controlled
   redirect used for token-exchange failures.
   
   5. A separate provisioning failure can occur when `auth_user_oauth(userinfo)` is called at
   `docs/admin_docs/security/oauth.mdx:214`; only a returned `None` is handled at lines
   215-222, while database or role-synchronization exceptions remain uncaught and result in a
   server error. Wrap the complete callback flow or explicitly handle these failure classes.
   ```
   </details>
   
   [![Fix in Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=fa0f23316f4d442a845a61e88476d315&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [![Fix in VSCode Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=fa0f23316f4d442a845a61e88476d315&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/admin_docs/security/oauth.mdx
   **Line:** 197:199
   **Comment:**
   	*Possible Bug: The custom callback only handles exceptions from `authorize_access_token()`. Failures from the userinfo request, HTTP status validation, JSON parsing, or user provisioning in the following code are uncaught and produce a server error instead of the controlled OAuth failure response described by this example. Wrap the entire callback processing flow in the error handling path or explicitly handle these failures.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=5cfdbc8fa2484cfd75f284a277ead976feb8942fe9935d2c633d77e137a5b89c&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=5cfdbc8fa2484cfd75f284a277ead976feb8942fe9935d2c633d77e137a5b89c&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-5115670393

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
         
   Refer to the <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "rusackas (via GitHub)" <gi...@apache.org>.
rusackas commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4770503820

   @albundy83 the content's genuinely useful — my one hangup is it's living in `kubernetes.mdx` but it's generic OAuth/Keycloak guidance. Mind moving it to a proper OAuth docs page? Then I'm happy to re-review.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "rusackas (via GitHub)" <gi...@apache.org>.
rusackas commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-6332019256

   Thanks for addressing everything mentioned. LGTM!


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2873336008


##########
docs/admin_docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,161 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+`Clients -> your-client-id -> Advanced -> Advanced settings`
+
+This code correctly handles the case where a user successfully authenticates with Keycloak but does not belong to any of the mapped groups.
+
+In that situation, the user is simply redirected back to the login page.
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    class CustomOAuthView(AuthOAuthView):
+        # Override the logout method to also log out from the OIDC provider
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+

Review Comment:
   **Suggestion:** The `logout` method in `CustomOAuthView` calls `session.clear()` and redirects to the OIDC provider, but it fails to call the parent class's `logout()` method (e.g., `super().logout()`). The parent method in `AuthOAuthView` handles critical cleanup such as calling Flask-Login's `logout_user()` to clear the authentication session and CSRF tokens. Without this, the user remains logged in to the Flask application even after the OIDC logout, creating a security vulnerability where the local session persists. [security]
   
   <details>
   <summary><b>Severity Level:</b> Critical 🚨</summary>
   
   ```mdx
   - ❌ Security vulnerability: Local Flask session persists after logout.
   - ❌ Users retain authenticated access to Superset after clicking logout.
   - ❌ Missing `logout_user()` call leaves remember-me cookies active.
   ```
   </details>
   
   ```suggestion
           @expose('/logout/', methods=['GET', 'POST'])
           def logout(self):
               session.clear()
               redirect_url = super().logout()
               return redirect(
                   f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
               )
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. User copies the `CustomOAuthView` class from `kubernetes.mdx:393` into their
   `superset_config.py` to implement Keycloak logout.
   
   2. User logs into Superset via OAuth (Keycloak) at the `/login/` endpoint, establishing a
   Flask-Login session with remember-me tokens.
   
   3. User clicks logout button which routes to `/logout/` handled by
   `CustomOAuthView.logout()` at line 396.
   
   4. The method executes `session.clear()` (line 397) clearing Flask session data but
   **fails to call `logout_user()`** from Flask-Login (normally handled by parent
   `AuthOAuthView.logout()`).
   
   5. The user is redirected to Keycloak logout (line 398-399), but upon returning to
   Superset, the Flask-Login session remains active (authentication cookies/tokens persist),
   allowing access to protected resources without re-authentication.
   
   6. **Security Impact**: User appears logged out from OIDC provider but retains active
   local session in Superset, creating a session fixation vulnerability where local
   application access persists after "logout".
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** docs/admin_docs/installation/kubernetes.mdx
   **Line:** 395:400
   **Comment:**
   	*Security: The `logout` method in `CustomOAuthView` calls `session.clear()` and redirects to the OIDC provider, but it fails to call the parent class's `logout()` method (e.g., `super().logout()`). The parent method in `AuthOAuthView` handles critical cleanup such as calling Flask-Login's `logout_user()` to clear the authentication session and CSRF tokens. Without this, the user remains logged in to the Flask application even after the OIDC logout, creating a security vulnerability where the local session persists.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=d766a88b08622e95c5dba3181c0a4c948f23e438a8defe4be86e42142bfedb90&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F38092&comment_hash=d766a88b08622e95c5dba3181c0a4c948f23e438a8defe4be86e42142bfedb90&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-3926301774

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2827000469


##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,121 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+Clients -> <your-client-id> -> Advanced -> Advanced settings
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+    import requests
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = 'Public'
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    # Custom OAuth view to handle logout redirection to Keycloak
+    class CustomOAuthView(AuthOAuthView):
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+
+
+    class CustomSsoSecurityManager(SupersetSecurityManager):
+        # Override the default OAuth view with our custom one
+        authoauthview = CustomOAuthView
+
+        # Override the method to fetch groups from the token and map them to Superset roles
+        def get_oauth_user_info(self, provider, response):
+            if provider == 'keycloak':
+                headers = {'Authorization': f"Bearer {response['access_token']}"}
+                resp = requests.get(OIDC_USERINFO_URL, headers=headers, timeout=5)
+
+                log.info(f'userinfo: {me}')
+
+                groups = me.get('groups', [])
+                if not groups:
+                    groups = ['Public']
+
+                return {
+                    'username': me.get('preferred_username'),
+                    'email': me.get('email'),
+                    'first_name': me.get('given_name'),
+                    'last_name': me.get('family_name'),
+                    'role_keys': groups,
+                }
+            return {}
+
+    # Set our custom security manager
+    CUSTOM_SECURITY_MANAGER = CustomSsoSecurityManager
+```
+

Review Comment:
   <div>
   
   
   <div id="suggestion">
   <div id="issue"><b>Incorrect OAuth role mapping</b></div>
   <div id="fix">
   
   The role_keys assignment in get_oauth_user_info does not match the AUTH_ROLES_MAPPING keys. The mapping uses prefixed keys like f'{CLIENT_ID}_admin', but role_keys is set to raw groups. This will prevent proper role assignment. Also, the default groups fallback uses 'Public' which doesn't correspond to any mapping key.
   </div>
   
   
   </div>
   
   
   
   
   <small><i>Code Review Run #c52ec5</i></small>
   </div><div>
   
   
   <div id="suggestion">
   <div id="issue"><b>Runtime error: undefined variable</b></div>
   <div id="fix">
   
   The variable 'me' is referenced throughout the method but never defined, which will cause a NameError at runtime when this OAuth path is executed. This appears to be an oversight in the documentation code example.
   </div>
   
   
   <details>
   <summary>
   <b>Code suggestion</b>
   </summary>
   <blockquote>Check the AI-generated fix before applying</blockquote>
   <div id="code">
   
   
   ```
    - resp = requests.get(OIDC_USERINFO_URL, headers=headers, timeout=5)
    - log.info(f'userinfo: {me}')
    + resp = requests.get(OIDC_USERINFO_URL, headers=headers, timeout=5)
    + me = resp.json()
    + log.debug(f'Received userinfo from OIDC provider for user {me.get(\"preferred_username\")}')
   ```
   
   </div>
   </details>
   
   
   
   </div>
   
   
   
   
   <small><i>Code Review Run #ae1161</i></small>
   </div><div>
   
   
   <div id="suggestion">
   <div id="issue"><b>Security: PII Logging Risk</b></div>
   <div id="fix">
   
   Logging the full userinfo dict at info level risks exposing PII like email, name, or other sensitive data. Consider logging only the username or a sanitized version.
   </div>
   
   
   </div>
   
   
   
   
   <small><i>Code Review Run #1ded16</i></small>
   </div>
   
   ---
   Should Bito avoid suggestions like this for future reviews? (<a href=https://alpha.bito.ai/home/ai-agents/review-rules>Manage Rules</a>)
   - [ ] Yes, avoid them



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] feat: Improve oauth doc [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r2834243042


##########
docs/docs/installation/kubernetes.mdx:
##########
@@ -308,6 +308,161 @@ configOverrides:
     AUTH_USER_REGISTRATION_ROLE = "Admin"
 ```
 
+:::note
+
+Here another example with groups mapping, logout from Keycloak and PKCE flow.
+
+You need to create a Secret that contains CLIENT_ID, CLIENT_SECRET and OIDC_ISSUER.
+
+Your oauth provider must be configured to support PKCE flow.
+
+For keycloak for example, you need to set 'Proof Key for Code Exchange Code Challenge Method' to value S256 under:
+`Clients -> your-client-id -> Advanced -> Advanced settings`
+
+This code correctly handles the case where a user successfully authenticates with Keycloak but does not belong to any of the mapped groups.
+
+In that situation, the user is simply redirected back to the login page.
+
+:::
+
+```yaml
+extraSecretEnv:
+  CLIENT_ID: my_superset_clientid
+  CLIENT_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  OIDC_ISSUER: https://myoauthprovider.youpi.fr/auth/realms/MYREALM
+
+configOverrides:
+  enable_oauth: |
+    from flask import redirect, request, session
+    from flask_appbuilder import expose
+    from flask_appbuilder.security.manager import AUTH_OAUTH
+    from flask_appbuilder.security.views import AuthOAuthView
+    from flask_login import login_user
+    from superset.security import SupersetSecurityManager
+    import logging
+    import os
+
+    log = logging.getLogger(__name__)
+
+    AUTH_TYPE = AUTH_OAUTH
+    AUTH_USER_REGISTRATION = True
+    AUTH_ROLES_SYNC_AT_LOGIN = True
+    AUTH_USER_REGISTRATION_ROLE = None
+
+    PROVIDER_NAME = 'keycloak'
+    CLIENT_ID = os.getenv('CLIENT_ID')
+    CLIENT_SECRET = os.getenv('CLIENT_SECRET')
+    OIDC_ISSUER = os.getenv('OIDC_ISSUER')
+    OIDC_BASE_URL = f'{OIDC_ISSUER}/protocol/openid-connect'
+    OIDC_AUTH_URL = f'{OIDC_BASE_URL}/auth'
+    OIDC_METADATA_URL = f'{OIDC_ISSUER}/.well-known/openid-configuration'
+    OIDC_TOKEN_URL = f'{OIDC_BASE_URL}/token'
+    OIDC_USERINFO_URL = f'{OIDC_BASE_URL}/userinfo'
+    OAUTH_PROVIDERS = [
+        {
+            'name': PROVIDER_NAME,
+            'token_key': 'access_token',
+            'icon': 'fa-circle-o',
+            'remote_app': {
+                'api_base_url': OIDC_BASE_URL,
+                'access_token_url': OIDC_TOKEN_URL,
+                'authorize_url': OIDC_AUTH_URL,
+                'request_token_url': None,
+                'server_metadata_url': OIDC_METADATA_URL,
+                'client_id': CLIENT_ID,
+                'client_secret': CLIENT_SECRET,
+                'client_kwargs': {
+                    'scope': 'openid email profile',
+                    'code_challenge_method': 'S256',
+                    'response_type': 'code',
+                },
+            },
+        }
+    ]
+
+    # Make sure you create these groups on Keycloak
+    AUTH_ROLES_MAPPING = {
+        f'{CLIENT_ID}_admin': ['Admin'],
+        f'{CLIENT_ID}_alpha': ['Alpha'],
+        f'{CLIENT_ID}_gamma': ['Gamma'],
+        f'{CLIENT_ID}_public': ['Public'],
+    }
+
+
+    class CustomOAuthView(AuthOAuthView):
+        # Override the logout method to also log out from the OIDC provider
+        @expose('/logout/', methods=['GET', 'POST'])
+        def logout(self):
+            session.clear()
+            return redirect(
+                f'{OIDC_ISSUER}/protocol/openid-connect/logout?post_logout_redirect_uri={request.url_root.strip("/")}&client_id={CLIENT_ID}'
+            )
+
+        # Override the authorized method to handle the OIDC callback and map groups to roles
+        @expose('/oauth-authorized/<provider>')
+        def oauth_authorized(self, provider):
+            # Step 1: exchange the authorization code for an access token
+            try:
+                resp = self.appbuilder.sm.oauth_remotes[provider].authorize_access_token()
+            except Exception as e:
+                log.exception(f'Error fetching access token: {e}')
+                return redirect(self.appbuilder.get_url_for_index)
+
+            # Step 2: fetch user info from the OIDC provider
+            userinfo = self.appbuilder.sm.get_oauth_user_info(provider, resp)
+            role_keys = userinfo.get('role_keys', [])
+            known_groups = [g for g in role_keys if g in AUTH_ROLES_MAPPING]
+
+            # Step 3: if no valid groups, redirect to the home page without login
+            if not known_groups:
+                log.warning(
+                    f'No valid groups for user {userinfo.get("username")}, groups received: {role_keys}'
+                )
+                return redirect(self.appbuilder.get_url_for_index)
+
+            # Step 4: create or retrieve the user in the database with their roles
+            userinfo['role_keys'] = known_groups
+            user = self.appbuilder.sm.auth_user_oauth(userinfo)
+            if user is None:
+                log.warning(
+                    f'auth_user_oauth returned None for user {userinfo.get("username")}'
+                )
+                return redirect(self.appbuilder.get_url_for_index)
+
+            # Step 5: login and redirect to the app
+            login_user(user, remember=False)
+            return redirect(self.appbuilder.get_url_for_index)
+
+
+    class CustomSsoSecurityManager(SupersetSecurityManager):
+        # Override the default OAuth view with our custom one
+        authoauthview = CustomOAuthView
+
+        # Override the method to fetch groups from the token and map them to Superset roles
+        def get_oauth_user_info(self, provider, response):
+            if provider == 'keycloak':
+                me = self.appbuilder.sm.oauth_remotes[provider].get(OIDC_USERINFO_URL)
+                me.raise_for_status()
+                data = me.json()
+                log.info(f'Received userinfo from OIDC provider for user {data}')

Review Comment:
   <div>
   
   
   <div id="suggestion">
   <div id="issue"><b>Security: Avoid logging PII</b></div>
   <div id="fix">
   
   The log.info statement logs the entire userinfo data dictionary, which includes personally identifiable information (PII) like email and name. This poses a privacy risk if logs are exposed. Change it to log only the username or remove the log if not essential.
   </div>
   
   
   <details>
   <summary>
   <b>Code suggestion</b>
   </summary>
   <blockquote>Check the AI-generated fix before applying</blockquote>
   <div id="code">
   
   
   ````suggestion
                   log.info(f'Received userinfo from OIDC provider for user {data.get("preferred_username")}')
   ````
   
   </div>
   </details>
   
   
   
   </div>
   
   
   
   
   <small><i>Code Review Run #662cb5</i></small>
   </div>
   
   ---
   Should Bito avoid suggestions like this for future reviews? (<a href=https://alpha.bito.ai/home/ai-agents/review-rules>Manage Rules</a>)
   - [ ] Yes, avoid them



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "albundy83 (via GitHub)" <gi...@apache.org>.
albundy83 commented on code in PR #38092:
URL: https://github.com/apache/superset/pull/38092#discussion_r3671466051


##########
docs/admin_docs/security/oauth.mdx:
##########
@@ -0,0 +1,269 @@
+---
+title: OAuth Configuration
+sidebar_position: 4
+---
+
+# Keycloak
+
+## Complete example: Keycloak with PKCE and group mapping
+
+This example demonstrates a complete Keycloak integration with Superset, including:
+
+* **PKCE** (Proof Key for Code Exchange) on top of a confidential client
+* **Group-to-role mapping**: Keycloak groups are mapped to Superset roles at every login (`AUTH_ROLES_SYNC_AT_LOGIN`)
+* **Access control**: users who authenticate successfully but do not belong to any mapped group are rejected with an explicit message instead of being silently logged in
+* **Single logout** (RP-Initiated Logout): logging out of Superset also terminates the Keycloak SSO session, using `id_token_hint`
+
+## Prerequisites: Keycloak client configuration
+
+### 1. Client settings
+
+Create a confidential OIDC client (e.g. `my_superset_clientid`) with:
+
+* **Valid redirect URIs**: `https://<superset-host>/oauth-authorized/keycloak`
+* **Valid post logout redirect URIs**: `https://<superset-host>` — required for the single-logout redirect to be accepted by Keycloak
+
+### 2. Enable PKCE
+
+Set **Proof Key for Code Exchange Code Challenge Method** to **S256** under:
+
+`Clients -> my_superset_clientid -> Advanced -> Advanced settings`
+
+### 3. Expose group membership in the userinfo response
+
+:::warning
+Keycloak does **not** expose a `groups` claim by default. Without this mapper, every user will be rejected with "no valid groups" even if they are correctly assigned in Keycloak.
+:::
+
+Add a **Group Membership** mapper to the client:
+
+`Clients -> my_superset_clientid -> Client scopes -> my_superset_clientid-dedicated -> Add mapper -> By configuration -> Group Membership`
+
+* **Token Claim Name**: `groups`
+* **Full group path**: **OFF** — otherwise groups are returned as `/my_superset_clientid_admin` (with a leading slash) and the role mapping will silently fail
+* **Add to userinfo**: **ON**
+
+### 4. Create the groups
+
+Make sure the following groups exist in Keycloak and that users are assigned to at least one of them:
+
+* `<my_superset_clientid>_admin`
+* `<my_superset_clientid>_alpha`
+* `<my_superset_clientid>_gamma`
+* `<my_superset_clientid>_public`
+
+The mapping between Keycloak groups and Superset roles is defined by `AUTH_ROLES_MAPPING` in the configuration below. Users who do not belong to any of the mapped groups are shown an explicit access-denied page, without being logged in.
+
+:::note
+This example deliberately renders the access-denied page directly from the OAuth callback instead of using Flask `flash()` messages. Starting with the React-based login page (Superset 6.x lineage), flash messages are no longer displayed anywhere in the UI, so a `flash()` + redirect would fail silently and the user would bounce between Superset and Keycloak (whose SSO session is still active) with no explanation. A directly rendered response works on every Superset version. The `AuthOAuthView` subclassing pattern itself still works on 6.x because the `/oauth-authorized/<provider>` callback route is still served by Flask-AppBuilder — but verify against your target version, as login-flow extension points are being reworked.
+:::
+
+:::note
+The issuer URL format depends on your Keycloak version. Legacy (Wildfly-based, < 17) distributions use `https://<keycloak-host>/auth/realms/<REALM>`, while modern (Quarkus-based) distributions use `https://<keycloak-host>/realms/<REALM>` — without the `/auth` prefix.
+:::
+
+## Kubernetes Secret
+
+Create a Secret containing the OIDC credentials, so they never appear in your Helm values (and therefore never end up in Git):
+
+```bash
+kubectl create secret generic superset-oidc \
+  --namespace superset \
+  --from-literal=CLIENT_ID='my_superset_clientid' \
+  --from-literal=CLIENT_SECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
+  --from-literal=OIDC_ISSUER='https://mykeycloak.youpi.fr/realms/MYREALM'
+```
+
+In a GitOps workflow, prefer provisioning this Secret through your secret management tooling (e.g. External Secrets Operator, Sealed Secrets) rather than creating it imperatively.
+
+## Helm chart configuration
+
+Reference the Secret with `envFromSecret` instead of putting values in `extraSecretEnv`:
+
+```yaml
+envFromSecret: superset-oidc

Review Comment:
   Totally true, fixed



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] docs(auth): add Keycloak PKCE, logout and group-mapping example [superset]

Posted by "albundy83 (via GitHub)" <gi...@apache.org>.
albundy83 commented on PR #38092:
URL: https://github.com/apache/superset/pull/38092#issuecomment-4927083598

   Hello @rusackas,
   
   I have updated my pull request based on your feedback and addressed your requests.
   
   I hope it now meets your expectations. 🙂


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org