Skip to content

Conversation

@auslin-aot
Copy link
Contributor

@auslin-aot auslin-aot commented Oct 27, 2025

User description

Issue Tracking

JIRA:
Issue Type: BUG/ FEATURE
https://aottech.atlassian.net/browse/FWF-5395
DEPENDENCY PR:

Changes

  • Upgraded Keycloak version from 26.1.2 to 26.4.1.

  • Renamed the realm file to match the realm name, resolving the error while upgrading: “File name/realm name mismatch. formsflow-ai-realm.json contains realm forms-flow-ai. File name should be forms-flow-ai-realm.json.”

Screenshots

image image

Notes

Checklist

  • Updated changelog
  • Added meaningful title for pull request

PR Type

Enhancement, Bug fix


Description

  • Upgrade Keycloak to 26.4.1

  • Align realm file name with realm

  • Update Docker compose Keycloak image

  • Bump Netty HTTP/2 dependency


Diagram Walkthrough

flowchart LR
  KCImg["Docker compose Keycloak image 26.4.1"]
  RealmFix["Realm file rename logic in customizations"]
  PomVer["idp-selector pom: Keycloak 26.4.1, Netty 4.2.6"]
  RealmJson["Add realm export: forms-flow-ai-realm.json"]
  Changelog["Changelog: upgrade notes"]

  KCImg -- "runtime upgrade" --> RealmJson
  RealmFix -- "ensure filename matches realm" --> RealmJson
  PomVer -- "align extensions with KC 26.4.1" --> KCImg
  Changelog -- "documents upgrade" --> KCImg
Loading

File Walkthrough

Relevant files
Documentation
CHANGELOG.md
Changelog notes for Keycloak upgrade                                         

CHANGELOG.md

  • Add upgrade notes section.
  • Document Keycloak upgrade to 26.4.1.
+4/-0     
Enhancement
docker-compose.yml
Docker compose image bump and realm rename hook                   

forms-flow-idm/keycloak/docker-compose.yml

  • Upgrade Keycloak image to 26.4.1.
  • Add shell command to rename realm file if mismatched.
  • Keep customization container alive for debugging.
+10/-2   
Dependencies
pom.xml
Align extension deps with Keycloak 26.4.1                               

forms-flow-idm/keycloak/idp-selector/pom.xml

  • Bump Keycloak version property to 26.4.1.
  • Update Netty HTTP/2 to 4.2.6.Final.
+2/-2     
Configuration changes
forms-flow-ai-realm.json
Add full Keycloak realm configuration export                         

forms-flow-idm/keycloak/imports/forms-flow-ai-realm.json

  • Add full realm export for forms-flow-ai.
  • Define roles, groups, users, clients, and scopes.
  • Configure protocol mappers and events.
  • Ensure realm name matches file name.
[link]   

@sonarqubecloud
Copy link

@github-actions
Copy link

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 Security concerns

Sensitive information exposure:
The realm JSON includes a concrete client secret for forms-flow-bpm and hashed admin credentials with configuration that could be used across environments. Consider removing or templating secrets and rotating existing ones.
Open redirect / token leakage risk: Clients forms-flow-analytics and forms-flow-web include * in redirectUris and webOrigins. This broad allowance can enable token interception. Restrict to explicit origins/redirects per environment.
Container hardening: The customization container executes an interactive shell and tails indefinitely, which may expand the attack surface. Ensure it is disabled or gated outside debugging scenarios.

⚡ Recommended focus areas for review

Long-running Container

The keycloak-customizations service now runs tail -f /dev/null, leaving the container alive indefinitely. Confirm this is intended for production and that lifecycle/healthchecks won't be impacted or block deployments.

command: |
  /bin/sh -c "
  if [ -f /custom/imports/formsflow-ai-realm.json ]; then
    echo 'Renaming realm file to correct name...'
    mv -f /custom/imports/formsflow-ai-realm.json /custom/imports/forms-flow-ai-realm.json
  fi
  # Keep container alive for debugging
  tail -f /dev/null
  "
Secret in Config

The realm export embeds a client secret and hashed admin credentials. Validate that these are safe for the target environment and consider using environment-specific secrets or removing them from VCS.

{
  "id": "forms-flow-ai",
  "realm": "forms-flow-ai",
  "loginTheme": "formsflow",
  "enabled": true,
  "registrationAllowed": true,
  "bruteForceProtected": true,
  "permanentLockout": false,
  "maxTemporaryLockouts": 0,
  "maxFailureWaitSeconds": 900,
  "minimumQuickLoginWaitSeconds": 60,
  "waitIncrementSeconds": 60,
  "quickLoginCheckMilliSeconds": 1000,
  "maxDeltaTimeSeconds": 1800,
  "failureFactor": 5,
  "roles": {
    "client": {
      "forms-flow-web": [
        {
          "name": "manage_users",
          "description": "Manage users",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "view_designs",
          "description": "View forms & flows",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "create_designs",
          "description": "Manage forms & flows you create and that are shared with you",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "view_filters",
          "description": "View filters",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "manage_roles",
          "description": "Manage roles",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "manage_integrations",
          "description": "Manage integrations",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "view_dashboards",
          "description": "View dashboards",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "manage_tasks",
          "description": "Work on tasks (assign to themselves + complete tasks)",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "create_submissions",
          "description": "Manage submissions (create, save drafts, resubmit)",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "create_filters",
          "description": "Manage personal filters",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "view_tasks",
          "description": "View tasks",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "manage_dashboard_authorizations",
          "description": "Manage dashboards",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "view_submissions",
          "description": "View their own past submissions",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "manage_all_filters",
          "description": "Manage all shared filters (delete and edit filters others shared, excluding private filters)",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "analyze_metrics_view",
          "description": "View metrics",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "analyze_process_view",
          "description": "View submissions process diagram",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "analyze_submissions_view",
          "description": "View submissions",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "analyze_submissions_view_history",
          "description": "View submissions history",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "assign_task_to_others",
          "description": "Assign/re-assign tasks to anybody within the group",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "manage_advance_workflows",
          "description": "Manage advance flows (BPMNs + SubFlows + Decision Tables)",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "manage_bundles",
          "description": "Manage bundles",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "manage_links",
          "description": "View links",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "manage_templates",
          "description": "Manage templates",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "reviewer_view_history",
          "description": "View task history",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "submission_view_history",
          "description": "View submission history",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        },
        {
          "name": "reviewer_process_view",
          "description": "View process diagram in task",
          "composite": false,
          "clientRole": true,
          "attributes": {}
        }
      ],
      "forms-flow-bpm": [],
      "forms-flow-analytics": []
    }
  },
  "groups": [
    {
      "name": "camunda-admin",
      "path": "/camunda-admin",
      "subGroups": [],
      "attributes": {
        "description": ["Camunda Administrator Role."]
      },
      "realmRoles": [],
      "clientRoles": {}
    },
    {
      "name": "formsflow",
      "path": "/formsflow",
      "subGroups": [
        {
          "name": "formsflow-admin",
          "path": "/formsflow/formsflow-admin",
          "subGroups": [],
          "attributes": {
            "description": ["Administrator Role."]
          },
          "realmRoles": [],
          "clientRoles": {
            "realm-management": [
              "query-groups",
              "view-users",
              "manage-clients",
              "query-clients",
              "view-authorization",
              "query-users",
              "manage-users",
              "create-client",
              "view-clients"
            ],
            "forms-flow-web": [
              "manage_users",
              "manage_roles",
              "manage_dashboard_authorizations",
              "manage_links"
            ]
          }
        },
        {
          "name": "formsflow-client",
          "path": "/formsflow/formsflow-client",
          "subGroups": [],
          "attributes": {
            "description": ["Client role to create & view submissions."]
          },
          "realmRoles": [],
          "clientRoles": {
            "forms-flow-web": ["create_submissions", "view_submissions", "submission_view_history"]
          }
        },
        {
          "name": "formsflow-designer",
          "path": "/formsflow/formsflow-designer",
          "subGroups": [],
          "attributes": {
            "description": ["Designer role to create forms and workflows."]
          },
          "realmRoles": [],
          "clientRoles": {
            "forms-flow-web": [
              "view_designs",
              "create_designs",
              "manage_advance_workflows"
            ]
          }
        },
        {
          "name": "formsflow-reviewer",
          "path": "/formsflow/formsflow-reviewer",
          "subGroups": [
            {
              "name": "approver",
              "path": "/formsflow/formsflow-reviewer/approver",
              "subGroups": [],
              "attributes": {
                "description": ["Staff role for reviewing tasks."]
              },
              "realmRoles": [],
              "clientRoles": {
                "forms-flow-web": ["manage_tasks", "view_tasks", "view_filters", "create_filters", "assign_task_to_others", "reviewer_view_history"]
              }
            },
            {
              "name": "clerk",
              "path": "/formsflow/formsflow-reviewer/clerk",
              "subGroups": [],
              "attributes": {
                "description": ["Staff role for reviewing tasks."]
              },
              "realmRoles": [],
              "clientRoles": {
                "forms-flow-web": ["manage_tasks", "view_tasks", "view_filters", "assign_task_to_others", "reviewer_view_history"]
              }
            }
          ],
          "attributes": {
            "description": [
              "Staff role for monitoring submissions and performing tasks."
            ]
          },
          "realmRoles": [],
          "clientRoles": {
            "forms-flow-web": [
              "view_dashboards",
              "manage_tasks",
              "view_tasks",
              "create_filters",
              "view_filters",
              "assign_task_to_others",
              "reviewer_view_history",
              "manage_all_filters",
              "analyze_metrics_view"
            ]
          }
        }
      ],
      "attributes": {},
      "realmRoles": [],
      "clientRoles": {}
    },
    {
      "name": "formsflow-analytics",
      "path": "/formsflow-analytics",
      "subGroups": [
        {
          "name": "group1",
          "path": "/formsflow-analytics/group1",
          "subGroups": [],
          "attributes": {
            "description": ["Role with dashboard authorization."]
          },
          "realmRoles": [],
          "clientRoles": {
            "forms-flow-web": ["view_dashboards"]
          }
        },
        {
          "name": "group2",
          "path": "/formsflow-analytics/group2",
          "subGroups": [],
          "attributes": {
            "description": ["Role with dashboard authorization."]
          },
          "realmRoles": [],
          "clientRoles": {
            "forms-flow-web": ["view_dashboards"]
          }
        }
      ],
      "attributes": {
        "description": ["Role with dashboard authorization."]
      },
      "realmRoles": [],
      "clientRoles": {
        "forms-flow-web": ["view_dashboards"]
      }
    }
  ],
  "users": [
    {
      "username": "formsflow-admin",
      "firstName": "ff",
      "lastName": "admin",
      "email": "formsflow-admin@aot-technologies.com",
      "emailVerified": false,
      "createdTimestamp": 1718023583532,
      "enabled": true,
      "totp": false,
      "credentials": [
        {
          "type": "password",
          "userLabel": "My password",
          "createdDate": 1718087465595,
          "secretData": "{\"value\":\"EpHuQHA+nMza4usSNWSDxl6bZ9pbKFe4vOjuMMEZijQ=\",\"salt\":\"Ht1p7xh28sqw6+FZ1ICcOg==\",\"additionalParameters\":{}}",
          "credentialData": "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}"
        }
      ],
      "disableableCredentialTypes": [],
      "requiredActions": ["UPDATE_PASSWORD"],
      "realmRoles": ["default-roles-forms-flow-ai"],
      "notBefore": 0,
      "groups": [
        "/camunda-admin",
        "/formsflow/formsflow-admin",
        "/formsflow-analytics"
      ]
    },
    {
      "username": "service-account-forms-flow-bpm",
      "emailVerified": false,
      "createdTimestamp": 1621585233480,
      "enabled": true,
      "totp": false,
      "serviceAccountClientId": "forms-flow-bpm",
      "credentials": [],
      "disableableCredentialTypes": [],
      "requiredActions": [],
      "realmRoles": ["offline_access", "uma_authorization"],
      "clientRoles": {
        "realm-management": [
          "query-users",
          "query-groups",
          "view-users",
          "manage-users",
          "manage-clients",
          "realm-admin"
        ],
        "forms-flow-web": ["view_submissions"],
        "account": ["view-profile", "manage-account"]
      },
      "notBefore": 0,
      "groups": ["/camunda-admin"]
    }
  ],
  "clients": [
    {
      "clientId": "forms-flow-analytics",
      "description": "Redash-Analytics",
      "adminUrl": "http://localhost:7000/saml/callback?org_slug=default",
      "surrogateAuthRequired": false,
      "enabled": true,
      "alwaysDisplayInConsole": false,
      "clientAuthenticatorType": "client-secret",
      "redirectUris": ["http://localhost:7000/*", "*"],
      "webOrigins": [],
      "notBefore": 0,
      "bearerOnly": false,
      "consentRequired": false,
      "standardFlowEnabled": true,
      "implicitFlowEnabled": false,
      "directAccessGrantsEnabled": true,
      "serviceAccountsEnabled": false,
      "publicClient": true,
      "frontchannelLogout": false,
      "protocol": "saml",
      "attributes": {
        "saml.assertion.signature": "true",
        "saml.force.post.binding": "false",
        "saml.multivalued.roles": "false",
        "saml.encrypt": "false",
        "post.logout.redirect.uris": "+",
        "saml.server.signature": "false",
        "saml.server.signature.keyinfo.ext": "false",
        "exclude.session.state.from.auth.response": "false",
        "saml.artifact.binding.identifier": "OOFH7REqnhW7gnm7DkWoK9smSR4=",
        "saml.signature.algorithm": "RSA_SHA256",
        "saml_force_name_id_format": "false",
        "saml.client.signature": "false",
        "tls.client.certificate.bound.access.tokens": "false",
        "saml.authnstatement": "true",
        "display.on.consent.screen": "false",
        "saml_name_id_format": "email",
        "saml.onetimeuse.condition": "false",
        "saml_signature_canonicalization_method": "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
      },
      "authenticationFlowBindingOverrides": {},
      "fullScopeAllowed": true,
      "nodeReRegistrationTimeout": -1,
      "protocolMappers": [
        {
          "name": "X500 surname",
          "protocol": "saml",
          "protocolMapper": "saml-user-property-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "lastName",
            "friendly.name": "LastName",
            "attribute.name": "urn:oid:2.5.4.4"
          }
        },
        {
          "name": "X500 givenName",
          "protocol": "saml",
          "protocolMapper": "saml-user-property-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "firstName",
            "friendly.name": "FirstName",
            "attribute.name": "urn:oid:2.5.4.42"
          }
        }
      ],
      "defaultClientScopes": ["role_list"],
      "optionalClientScopes": []
    },
    {
      "clientId": "forms-flow-bpm",
      "description": "Camunda Process Engine Components",
      "surrogateAuthRequired": false,
      "enabled": true,
      "alwaysDisplayInConsole": false,
      "clientAuthenticatorType": "client-secret",
      "secret": "e4bdbd25-1467-4f7f-b993-bc4b1944c943",
      "redirectUris": ["http://localhost:8000/camunda/*", "*"],
      "webOrigins": ["*"],
      "notBefore": 0,
      "bearerOnly": false,
      "consentRequired": false,
      "standardFlowEnabled": true,
      "implicitFlowEnabled": false,
      "directAccessGrantsEnabled": true,
      "serviceAccountsEnabled": true,
      "publicClient": false,
      "frontchannelLogout": false,
      "protocol": "openid-connect",
      "attributes": {
        "saml.assertion.signature": "false",
        "saml.force.post.binding": "false",
        "saml.multivalued.roles": "false",
        "saml.encrypt": "false",
        "post.logout.redirect.uris": "+",
        "saml.server.signature": "false",
        "saml.server.signature.keyinfo.ext": "false",
        "exclude.session.state.from.auth.response": "false",
        "saml_force_name_id_format": "false",
        "saml.client.signature": "false",
        "tls.client.certificate.bound.access.tokens": "false",
        "saml.authnstatement": "false",
        "display.on.consent.screen": "false",
        "saml.onetimeuse.condition": "false"
      },
      "authenticationFlowBindingOverrides": {},
      "fullScopeAllowed": true,
      "nodeReRegistrationTimeout": -1,
      "protocolMappers": [
        {
          "name": "formsflow-web-mapper",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-audience-mapper",
          "consentRequired": false,
          "config": {
            "included.client.audience": "forms-flow-web",
            "id.token.claim": "false",
            "access.token.claim": "true",
            "userinfo.token.claim": "false"
          }
        },
        {
          "name": "Client Host",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usersessionmodel-note-mapper",
          "consentRequired": false,
          "config": {
            "user.session.note": "clientHost",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "clientHost",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "username",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-property-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "username",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "preferred_username",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "Client IP Address",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usersessionmodel-note-mapper",
          "consentRequired": false,
          "config": {
            "user.session.note": "clientAddress",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "clientAddress",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "groups",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-group-membership-mapper",
          "consentRequired": false,
          "config": {
            "full.path": "true",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "groups",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "camunda-rest-api",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-audience-mapper",
          "consentRequired": false,
          "config": {
            "id.token.claim": "false",
            "access.token.claim": "true",
            "included.custom.audience": "camunda-rest-api",
            "userinfo.token.claim": "false"
          }
        },
        {
          "name": "Client ID",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usersessionmodel-note-mapper",
          "consentRequired": false,
          "config": {
            "user.session.note": "clientId",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "clientId",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        }
      ],
      "defaultClientScopes": [
        "web-origins",
        "roles",
        "profile",
        "basic",
        "camunda-rest-api",
        "email"
      ],
      "optionalClientScopes": [
        "address",
        "phone",
        "offline_access",
        "microprofile-jwt"
      ]
    },
    {
      "clientId": "forms-flow-web",
      "description": "React based FormIO web components",
      "surrogateAuthRequired": false,
      "enabled": true,
      "alwaysDisplayInConsole": false,
      "clientAuthenticatorType": "client-secret",
      "redirectUris": ["http://localhost:3000/*", "*"],
      "webOrigins": ["*"],
      "notBefore": 0,
      "bearerOnly": false,
      "consentRequired": false,
      "standardFlowEnabled": true,
      "implicitFlowEnabled": false,
      "directAccessGrantsEnabled": true,
      "serviceAccountsEnabled": false,
      "publicClient": true,
      "frontchannelLogout": false,
      "protocol": "openid-connect",
      "attributes": {
        "saml.assertion.signature": "false",
        "saml.force.post.binding": "false",
        "saml.multivalued.roles": "false",
        "saml.encrypt": "false",
        "post.logout.redirect.uris": "+",
        "saml.server.signature": "false",
        "saml.server.signature.keyinfo.ext": "false",
        "exclude.session.state.from.auth.response": "false",
        "saml_force_name_id_format": "false",
        "saml.client.signature": "false",
        "tls.client.certificate.bound.access.tokens": "false",
        "saml.authnstatement": "false",
        "display.on.consent.screen": "false",
        "saml.onetimeuse.condition": "false"
      },
      "authenticationFlowBindingOverrides": {},
      "fullScopeAllowed": true,
      "nodeReRegistrationTimeout": -1,
      "protocolMappers": [
        {
          "name": "camunda-rest-api",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-audience-mapper",
          "consentRequired": false,
          "config": {
            "id.token.claim": "false",
            "access.token.claim": "true",
            "included.custom.audience": "camunda-rest-api",
            "userinfo.token.claim": "false"
          }
        },
        {
          "name": "formsflow-web-mapper",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-audience-mapper",
          "consentRequired": false,
          "config": {
            "included.client.audience": "forms-flow-web",
            "id.token.claim": "false",
            "access.token.claim": "true",
            "userinfo.token.claim": "false"
          }
        },
        {
          "name": "groups",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-group-membership-mapper",
          "consentRequired": false,
          "config": {
            "full.path": "true",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "groups",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "dashboard-mapper",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "aggregate.attrs": "true",
            "userinfo.token.claim": "true",
            "multivalued": "true",
            "user.attribute": "dashboards",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "dashboards"
          }
        }
      ],
      "defaultClientScopes": [
        "web-origins",
        "roles",
        "profile",
        "basic",
        "camunda-rest-api",
        "email"
      ],
      "optionalClientScopes": [
        "address",
        "phone",
        "offline_access",
        "microprofile-jwt"
      ]
    }
  ],
  "clientScopes": [
    {
      "name": "address",
      "description": "OpenID Connect built-in scope: address",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "true",
        "consent.screen.text": "${addressScopeConsentText}",
        "display.on.consent.screen": "true"
      },
      "protocolMappers": [
        {
          "id": "5d9b4833-6472-4de5-8a32-ac8111d77aa1",
          "name": "address",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-address-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute.formatted": "formatted",
            "user.attribute.country": "country",
            "user.attribute.postal_code": "postal_code",
            "userinfo.token.claim": "true",
            "user.attribute.street": "street",
            "id.token.claim": "true",
            "user.attribute.region": "region",
            "access.token.claim": "true",
            "user.attribute.locality": "locality"
          }
        }
      ]
    },
    {
      "name": "acr",
      "description": "OpenID Connect scope for add acr (authentication context class reference) to the token",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "false",
        "display.on.consent.screen": "false"
      },
      "protocolMappers": [
        {
          "name": "acr loa level",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-acr-mapper",
          "consentRequired": false,
          "config": {
            "id.token.claim": "true",
            "introspection.token.claim": "true",
            "access.token.claim": "true",
            "userinfo.token.claim": "true"
          }
        }
      ]
    },
    {
      "name": "microprofile-jwt",
      "description": "Microprofile - JWT built-in scope",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "true",
        "display.on.consent.screen": "false"
      },
      "protocolMappers": [
        {
          "name": "upn",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-property-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "username",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "upn",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "groups",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-realm-role-mapper",
          "consentRequired": false,
          "config": {
            "multivalued": "true",
            "userinfo.token.claim": "true",
            "user.attribute": "foo",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "groups",
            "jsonType.label": "String"
          }
        }
      ]
    },
    {
      "name": "roles",
      "description": "OpenID Connect scope for add user roles to the access token",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "false",
        "consent.screen.text": "${rolesScopeConsentText}",
        "display.on.consent.screen": "true"
      },
      "protocolMappers": [
        {
          "name": "Role",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-client-role-mapper",
          "consentRequired": false,
          "config": {
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "role",
            "usermodel.clientRoleMapping.clientId": "forms-flow-web",
            "multivalued": "true",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "client roles",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-client-role-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "foo",
            "access.token.claim": "true",
            "claim.name": "resource_access.${client_id}.roles",
            "jsonType.label": "String",
            "multivalued": "true"
          }
        },
        {
          "name": "realm roles",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-realm-role-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "foo",
            "access.token.claim": "true",
            "claim.name": "realm_access.roles",
            "jsonType.label": "String",
            "multivalued": "true"
          }
        },
        {
          "name": "audience resolve",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-audience-resolve-mapper",
          "consentRequired": false,
          "config": {}
        }
      ]
    },
    {
      "name": "offline_access",
      "description": "OpenID Connect built-in scope: offline_access",
      "protocol": "openid-connect",
      "attributes": {
        "consent.screen.text": "${offlineAccessScopeConsentText}",
        "display.on.consent.screen": "true"
      }
    },
    {
      "name": "basic",
      "description": "OpenID Connect scope for add all basic claims to the token",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "false",
        "display.on.consent.screen": "false"
      },
      "protocolMappers": [
        {
          "name": "sub",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-sub-mapper",
          "consentRequired": false,
          "config": {
            "introspection.token.claim": "true",
            "access.token.claim": "true"
          }
        },
        {
          "name": "auth_time",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usersessionmodel-note-mapper",
          "consentRequired": false,
          "config": {
            "user.session.note": "AUTH_TIME",
            "id.token.claim": "true",
            "introspection.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "auth_time",
            "jsonType.label": "long"
          }
        }
      ]
    },
    {
      "name": "email",
      "description": "OpenID Connect built-in scope: email",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "true",
        "consent.screen.text": "${emailScopeConsentText}",
        "display.on.consent.screen": "true"
      },
      "protocolMappers": [
        {
          "name": "email",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-property-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "email",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "email",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "email verified",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-property-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "emailVerified",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "email_verified",
            "jsonType.label": "boolean",
            "userinfo.token.claim": "true"
          }
        }
      ]
    },
    {
      "name": "web-origins",
      "description": "OpenID Connect scope for add allowed web origins to the access token",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "false",
        "consent.screen.text": "",
        "display.on.consent.screen": "false"
      },
      "protocolMappers": [
        {
          "name": "allowed web origins",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-allowed-origins-mapper",
          "consentRequired": false,
          "config": {}
        }
      ]
    },
    {
      "name": "role_list",
      "description": "SAML role list",
      "protocol": "saml",
      "attributes": {
        "consent.screen.text": "${samlRoleListScopeConsentText}",
        "display.on.consent.screen": "true"
      },
      "protocolMappers": [
        {
          "name": "role list",
          "protocol": "saml",
          "protocolMapper": "saml-role-list-mapper",
          "consentRequired": false,
          "config": {
            "single": "false",
            "attribute.nameformat": "Basic",
            "attribute.name": "Role"
          }
        }
      ]
    },
    {
      "name": "camunda-rest-api",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "true",
        "display.on.consent.screen": "true"
      },
      "protocolMappers": [
        {
          "name": "camunda-rest-api",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-audience-mapper",
          "consentRequired": false,
          "config": {
            "id.token.claim": "false",
            "access.token.claim": "true",
            "included.custom.audience": "camunda-rest-api",
            "userinfo.token.claim": "false"
          }
        }
      ]
    },
    {
      "name": "profile",
      "description": "OpenID Connect built-in scope: profile",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "true",
        "consent.screen.text": "${profileScopeConsentText}",
        "display.on.consent.screen": "true"
      },
      "protocolMappers": [
        {
          "name": "zoneinfo",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "zoneinfo",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "zoneinfo",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "gender",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "gender",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "gender",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "picture",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "picture",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "picture",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "username",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-property-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "username",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "preferred_username",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "website",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "website",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "website",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "locale",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "locale",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "locale",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "middle name",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "middleName",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "middle_name",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "nickname",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "nickname",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "nickname",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "profile",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "profile",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "profile",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "birthdate",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "birthdate",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "birthdate",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "full name",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-full-name-mapper",
          "consentRequired": false,
          "config": {
            "id.token.claim": "true",
            "access.token.claim": "true",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "updated at",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "updatedAt",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "updated_at",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "family name",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-property-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "lastName",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "family_name",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "given name",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-property-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "firstName",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "given_name",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        }
      ]
    },
    {
      "name": "phone",
      "description": "OpenID Connect built-in scope: phone",
      "protocol": "openid-connect",
      "attributes": {
        "include.in.token.scope": "true",
        "consent.screen.text": "${phoneScopeConsentText}",
        "display.on.consent.screen": "true"
      },
      "protocolMappers": [
        {
          "name": "phone number",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "phoneNumber",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "phone_number",
            "jsonType.label": "String",
            "userinfo.token.claim": "true"
          }
        },
        {
          "name": "phone number verified",
          "protocol": "openid-connect",
          "protocolMapper": "oidc-usermodel-attribute-mapper",
          "consentRequired": false,
          "config": {
            "user.attribute": "phoneNumberVerified",
            "id.token.claim": "true",
            "access.token.claim": "true",
            "claim.name": "phone_number_verified",
            "jsonType.label": "boolean",
            "userinfo.token.claim": "true"
          }
        }
      ]
    }
  ],
  "defaultDefaultClientScopes": [
    "role_list",
    "profile",
    "email",
    "roles",
    "web-origins",
    "camunda-rest-api",
    "acr",
    "basic"
  ],
  "defaultOptionalClientScopes": [
    "offline_access",
    "address",
    "phone",
    "microprofile-jwt"
  ],
  "eventsEnabled": true,
  "eventsExpiration": 1800,
  "eventsListeners": ["jboss-logging"],
  "enabledEventTypes": [
    "UPDATE_CONSENT_ERROR",
    "SEND_RESET_PASSWORD",
    "GRANT_CONSENT",
    "VERIFY_PROFILE_ERROR",
    "UPDATE_TOTP",
    "REMOVE_TOTP",
    "REVOKE_GRANT",
    "LOGIN_ERROR",
    "CLIENT_LOGIN",
    "RESET_PASSWORD_ERROR",
    "IMPERSONATE_ERROR",
    "CODE_TO_TOKEN_ERROR",
    "CUSTOM_REQUIRED_ACTION",
    "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR",
    "RESTART_AUTHENTICATION",
    "UPDATE_PROFILE_ERROR",
    "IMPERSONATE",
    "LOGIN",
    "UPDATE_PASSWORD_ERROR",
    "OAUTH2_DEVICE_VERIFY_USER_CODE",
    "CLIENT_INITIATED_ACCOUNT_LINKING",
    "USER_DISABLED_BY_PERMANENT_LOCKOUT",
    "OAUTH2_EXTENSION_GRANT",
    "TOKEN_EXCHANGE",
    "REGISTER",
    "LOGOUT",
    "AUTHREQID_TO_TOKEN",
    "DELETE_ACCOUNT_ERROR",
    "CLIENT_REGISTER",
    "IDENTITY_PROVIDER_LINK_ACCOUNT",
    "USER_DISABLED_BY_TEMPORARY_LOCKOUT",
    "UPDATE_PASSWORD",
    "DELETE_ACCOUNT",
    "FEDERATED_IDENTITY_LINK_ERROR",
    "CLIENT_DELETE",
    "IDENTITY_PROVIDER_FIRST_LOGIN",
    "VERIFY_EMAIL",
    "CLIENT_DELETE_ERROR",
    "CLIENT_LOGIN_ERROR",
    "RESTART_AUTHENTICATION_ERROR",
    "REMOVE_FEDERATED_IDENTITY_ERROR",
    "EXECUTE_ACTIONS",
    "TOKEN_EXCHANGE_ERROR",
    "PERMISSION_TOKEN",
    "FEDERATED_IDENTITY_OVERRIDE_LINK",
    "SEND_IDENTITY_PROVIDER_LINK_ERROR",
    "EXECUTE_ACTION_TOKEN_ERROR",
    "SEND_VERIFY_EMAIL",
    "OAUTH2_EXTENSION_GRANT_ERROR",
    "OAUTH2_DEVICE_AUTH",
    "EXECUTE_ACTIONS_ERROR",
    "REMOVE_FEDERATED_IDENTITY",
    "OAUTH2_DEVICE_CODE_TO_TOKEN",
    "IDENTITY_PROVIDER_POST_LOGIN",
    "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR",
    "FEDERATED_IDENTITY_OVERRIDE_LINK_ERROR",
    "UPDATE_EMAIL",
    "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR",
    "REGISTER_ERROR",
    "REVOKE_GRANT_ERROR",
    "LOGOUT_ERROR",
    "UPDATE_EMAIL_ERROR",
    "EXECUTE_ACTION_TOKEN",
    "CLIENT_UPDATE_ERROR",
    "UPDATE_PROFILE",
    "AUTHREQID_TO_TOKEN_ERROR",
    "INVITE_ORG_ERROR",
    "FEDERATED_IDENTITY_LINK",
    "CLIENT_REGISTER_ERROR",
    "INVITE_ORG",
    "SEND_VERIFY_EMAIL_ERROR",
    "SEND_IDENTITY_PROVIDER_LINK",
    "RESET_PASSWORD",
    "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR",
    "OAUTH2_DEVICE_AUTH_ERROR",
    "UPDATE_CONSENT",
    "REMOVE_TOTP_ERROR",
    "VERIFY_EMAIL_ERROR",
    "SEND_RESET_PASSWORD_ERROR",
    "CLIENT_UPDATE",
    "IDENTITY_PROVIDER_POST_LOGIN_ERROR",
    "CUSTOM_REQUIRED_ACTION_ERROR",
    "UPDATE_TOTP_ERROR",
    "CODE_TO_TOKEN",
    "VERIFY_PROFILE",
    "GRANT_CONSENT_ERROR",
    "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR"
  ],
  "adminEventsEnabled": false,
  "adminEventsDetailsEnabled": false,
  "components": {
    "org.keycloak.userprofile.UserProfileProvider": [
      {
        "providerId": "declarative-user-profile",
        "subComponents": {},
        "config": {
          "kc.user.profile.config": [
            "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}"
          ]
        }
      }
    ]
  },
  "internationalizationEnabled": true,
  "supportedLocales": [
    "en"
  ],
  "defaultLocale": "en"
}
Wildcard Redirects

Several clients allow * in redirect URIs and web origins, which can enable token leakage. Verify these are limited to local/dev and locked down for production.

{
  "clientId": "forms-flow-analytics",
  "description": "Redash-Analytics",
  "adminUrl": "http://localhost:7000/saml/callback?org_slug=default",
  "surrogateAuthRequired": false,
  "enabled": true,
  "alwaysDisplayInConsole": false,
  "clientAuthenticatorType": "client-secret",
  "redirectUris": ["http://localhost:7000/*", "*"],
  "webOrigins": [],
  "notBefore": 0,
  "bearerOnly": false,
  "consentRequired": false,
  "standardFlowEnabled": true,
  "implicitFlowEnabled": false,
  "directAccessGrantsEnabled": true,
  "serviceAccountsEnabled": false,
  "publicClient": true,
  "frontchannelLogout": false,
  "protocol": "saml",
  "attributes": {
    "saml.assertion.signature": "true",
    "saml.force.post.binding": "false",
    "saml.multivalued.roles": "false",
    "saml.encrypt": "false",
    "post.logout.redirect.uris": "+",
    "saml.server.signature": "false",
    "saml.server.signature.keyinfo.ext": "false",
    "exclude.session.state.from.auth.response": "false",
    "saml.artifact.binding.identifier": "OOFH7REqnhW7gnm7DkWoK9smSR4=",
    "saml.signature.algorithm": "RSA_SHA256",
    "saml_force_name_id_format": "false",
    "saml.client.signature": "false",
    "tls.client.certificate.bound.access.tokens": "false",
    "saml.authnstatement": "true",
    "display.on.consent.screen": "false",
    "saml_name_id_format": "email",
    "saml.onetimeuse.condition": "false",
    "saml_signature_canonicalization_method": "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
  },
  "authenticationFlowBindingOverrides": {},
  "fullScopeAllowed": true,
  "nodeReRegistrationTimeout": -1,
  "protocolMappers": [
    {
      "name": "X500 surname",
      "protocol": "saml",
      "protocolMapper": "saml-user-property-mapper",
      "consentRequired": false,
      "config": {
        "user.attribute": "lastName",
        "friendly.name": "LastName",
        "attribute.name": "urn:oid:2.5.4.4"
      }
    },
    {
      "name": "X500 givenName",
      "protocol": "saml",
      "protocolMapper": "saml-user-property-mapper",
      "consentRequired": false,
      "config": {
        "user.attribute": "firstName",
        "friendly.name": "FirstName",
        "attribute.name": "urn:oid:2.5.4.42"
      }
    }
  ],
  "defaultClientScopes": ["role_list"],
  "optionalClientScopes": []
},
{
  "clientId": "forms-flow-bpm",
  "description": "Camunda Process Engine Components",
  "surrogateAuthRequired": false,
  "enabled": true,
  "alwaysDisplayInConsole": false,
  "clientAuthenticatorType": "client-secret",
  "secret": "e4bdbd25-1467-4f7f-b993-bc4b1944c943",
  "redirectUris": ["http://localhost:8000/camunda/*", "*"],
  "webOrigins": ["*"],
  "notBefore": 0,
  "bearerOnly": false,
  "consentRequired": false,
  "standardFlowEnabled": true,
  "implicitFlowEnabled": false,
  "directAccessGrantsEnabled": true,
  "serviceAccountsEnabled": true,
  "publicClient": false,
  "frontchannelLogout": false,
  "protocol": "openid-connect",
  "attributes": {
    "saml.assertion.signature": "false",
    "saml.force.post.binding": "false",
    "saml.multivalued.roles": "false",
    "saml.encrypt": "false",
    "post.logout.redirect.uris": "+",
    "saml.server.signature": "false",
    "saml.server.signature.keyinfo.ext": "false",
    "exclude.session.state.from.auth.response": "false",
    "saml_force_name_id_format": "false",
    "saml.client.signature": "false",
    "tls.client.certificate.bound.access.tokens": "false",
    "saml.authnstatement": "false",
    "display.on.consent.screen": "false",
    "saml.onetimeuse.condition": "false"
  },
  "authenticationFlowBindingOverrides": {},
  "fullScopeAllowed": true,
  "nodeReRegistrationTimeout": -1,
  "protocolMappers": [
    {
      "name": "formsflow-web-mapper",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-audience-mapper",
      "consentRequired": false,
      "config": {
        "included.client.audience": "forms-flow-web",
        "id.token.claim": "false",
        "access.token.claim": "true",
        "userinfo.token.claim": "false"
      }
    },
    {
      "name": "Client Host",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usersessionmodel-note-mapper",
      "consentRequired": false,
      "config": {
        "user.session.note": "clientHost",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "clientHost",
        "jsonType.label": "String",
        "userinfo.token.claim": "true"
      }
    },
    {
      "name": "username",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usermodel-property-mapper",
      "consentRequired": false,
      "config": {
        "user.attribute": "username",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "preferred_username",
        "jsonType.label": "String",
        "userinfo.token.claim": "true"
      }
    },
    {
      "name": "Client IP Address",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usersessionmodel-note-mapper",
      "consentRequired": false,
      "config": {
        "user.session.note": "clientAddress",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "clientAddress",
        "jsonType.label": "String",
        "userinfo.token.claim": "true"
      }
    },
    {
      "name": "groups",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-group-membership-mapper",
      "consentRequired": false,
      "config": {
        "full.path": "true",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "groups",
        "userinfo.token.claim": "true"
      }
    },
    {
      "name": "camunda-rest-api",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-audience-mapper",
      "consentRequired": false,
      "config": {
        "id.token.claim": "false",
        "access.token.claim": "true",
        "included.custom.audience": "camunda-rest-api",
        "userinfo.token.claim": "false"
      }
    },
    {
      "name": "Client ID",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usersessionmodel-note-mapper",
      "consentRequired": false,
      "config": {
        "user.session.note": "clientId",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "clientId",
        "jsonType.label": "String",
        "userinfo.token.claim": "true"
      }
    }
  ],
  "defaultClientScopes": [
    "web-origins",
    "roles",
    "profile",
    "basic",
    "camunda-rest-api",
    "email"
  ],
  "optionalClientScopes": [
    "address",
    "phone",
    "offline_access",
    "microprofile-jwt"
  ]
},
{
  "clientId": "forms-flow-web",
  "description": "React based FormIO web components",
  "surrogateAuthRequired": false,
  "enabled": true,
  "alwaysDisplayInConsole": false,
  "clientAuthenticatorType": "client-secret",
  "redirectUris": ["http://localhost:3000/*", "*"],
  "webOrigins": ["*"],
  "notBefore": 0,
  "bearerOnly": false,
  "consentRequired": false,
  "standardFlowEnabled": true,
  "implicitFlowEnabled": false,
  "directAccessGrantsEnabled": true,
  "serviceAccountsEnabled": false,
  "publicClient": true,
  "frontchannelLogout": false,
  "protocol": "openid-connect",
  "attributes": {
    "saml.assertion.signature": "false",
    "saml.force.post.binding": "false",
    "saml.multivalued.roles": "false",
    "saml.encrypt": "false",
    "post.logout.redirect.uris": "+",
    "saml.server.signature": "false",
    "saml.server.signature.keyinfo.ext": "false",
    "exclude.session.state.from.auth.response": "false",
    "saml_force_name_id_format": "false",
    "saml.client.signature": "false",
    "tls.client.certificate.bound.access.tokens": "false",
    "saml.authnstatement": "false",
    "display.on.consent.screen": "false",
    "saml.onetimeuse.condition": "false"
  },
  "authenticationFlowBindingOverrides": {},
  "fullScopeAllowed": true,
  "nodeReRegistrationTimeout": -1,
  "protocolMappers": [
    {
      "name": "camunda-rest-api",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-audience-mapper",
      "consentRequired": false,
      "config": {
        "id.token.claim": "false",
        "access.token.claim": "true",
        "included.custom.audience": "camunda-rest-api",
        "userinfo.token.claim": "false"
      }
    },
    {
      "name": "formsflow-web-mapper",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-audience-mapper",
      "consentRequired": false,
      "config": {
        "included.client.audience": "forms-flow-web",
        "id.token.claim": "false",
        "access.token.claim": "true",
        "userinfo.token.claim": "false"
      }
    },
    {
      "name": "groups",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-group-membership-mapper",
      "consentRequired": false,
      "config": {
        "full.path": "true",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "groups",
        "userinfo.token.claim": "true"
      }
    },
    {
      "name": "dashboard-mapper",
      "protocol": "openid-connect",
      "protocolMapper": "oidc-usermodel-attribute-mapper",
      "consentRequired": false,
      "config": {
        "aggregate.attrs": "true",
        "userinfo.token.claim": "true",
        "multivalued": "true",
        "user.attribute": "dashboards",
        "id.token.claim": "true",
        "access.token.claim": "true",
        "claim.name": "dashboards"
      }
    }
  ],
  "defaultClientScopes": [
    "web-origins",
    "roles",
    "profile",
    "basic",
    "camunda-rest-api",
    "email"
  ],
  "optionalClientScopes": [
    "address",
    "phone",
    "offline_access",
    "microprofile-jwt"
  ]
}

@github-actions
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Security
Restrict wildcard redirect URIs

Remove overly-broad wildcard entries in redirectUris as they pose a security risk
and can be rejected by newer Keycloak versions. Specify only the exact allowed
origins and redirect URIs to ensure compliant and secure behavior.

forms-flow-idm/keycloak/imports/forms-flow-ai-realm.json [434-435]

-"redirectUris": ["http://localhost:7000/*", "*"],
-"webOrigins": [],
+"redirectUris": ["http://localhost:7000/*"],
+"webOrigins": ["http://localhost:7000"],
Suggestion importance[1-10]: 8

__

Why: Removing "*" from redirectUris and defining webOrigins explicitly aligns with Keycloak best practices and newer restrictions, reducing security risk with accurate changes to the shown lines.

Medium
Remove permissive CORS and redirects

Avoid using "*" for redirectUris and webOrigins as it weakens security and may be
blocked by Keycloak 26.4.1. Replace with explicit application origins to prevent
open redirect and CORS issues.

forms-flow-idm/keycloak/imports/forms-flow-ai-realm.json [652-654]

-"redirectUris": ["http://localhost:3000/*", "*"],
-"webOrigins": ["*"],
+"redirectUris": ["http://localhost:3000/*"],
+"webOrigins": ["http://localhost:3000"],
Suggestion importance[1-10]: 8

__

Why: Replacing "*" with explicit origins for the web client mitigates open redirect and CORS issues and is compatible with newer Keycloak behavior; the proposed code matches the existing snippet's context.

Medium
Possible issue
Harden shell command execution

Quote the here-doc string properly to avoid YAML or shell parsing issues and ensure
the script exits on errors. Add set -euo pipefail and guard mv with -f already
present, then keep the container alive only if needed. This prevents silent failures
during the rename.

forms-flow-idm/keycloak/docker-compose.yml [61-69]

 command: |
-  /bin/sh -c "
+  /bin/sh -c 'set -euo pipefail
   if [ -f /custom/imports/formsflow-ai-realm.json ]; then
-    echo 'Renaming realm file to correct name...'
+    echo "Renaming realm file to correct name..."
     mv -f /custom/imports/formsflow-ai-realm.json /custom/imports/forms-flow-ai-realm.json
   fi
   # Keep container alive for debugging
   tail -f /dev/null
-  "
+  '
Suggestion importance[1-10]: 6

__

Why: Adding set -euo pipefail improves robustness and the quoting change avoids shell/YAML parsing pitfalls, but the current script already functions and the impact is moderate.

Low

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants