@cdmbase/wiki-browser 12.0.18-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/lib/components/Logo.d.ts +4 -0
- package/lib/components/Logo.d.ts.map +1 -0
- package/lib/components/Logo.js +16 -0
- package/lib/components/Logo.js.map +1 -0
- package/lib/components/help/SidebarSearch.d.ts +8 -0
- package/lib/components/help/SidebarSearch.d.ts.map +1 -0
- package/lib/components/help/SidebarSearch.js +111 -0
- package/lib/components/help/SidebarSearch.js.map +1 -0
- package/lib/components/help/index.d.ts +2 -0
- package/lib/components/help/index.d.ts.map +1 -0
- package/lib/components/landing/FeatureCard.d.ts +13 -0
- package/lib/components/landing/FeatureCard.d.ts.map +1 -0
- package/lib/components/landing/FeatureCard.js +85 -0
- package/lib/components/landing/FeatureCard.js.map +1 -0
- package/lib/components/landing/QuickLinkCard.d.ts +8 -0
- package/lib/components/landing/QuickLinkCard.d.ts.map +1 -0
- package/lib/components/landing/QuickLinkCard.js +26 -0
- package/lib/components/landing/QuickLinkCard.js.map +1 -0
- package/lib/components/landing/SearchInput.d.ts +10 -0
- package/lib/components/landing/SearchInput.d.ts.map +1 -0
- package/lib/components/landing/SearchInput.js +223 -0
- package/lib/components/landing/SearchInput.js.map +1 -0
- package/lib/components/landing/index.d.ts +4 -0
- package/lib/components/landing/index.d.ts.map +1 -0
- package/lib/components/welcome.d.ts +3 -0
- package/lib/components/welcome.d.ts.map +1 -0
- package/lib/compute.d.ts +4 -0
- package/lib/compute.d.ts.map +1 -0
- package/lib/compute.js +96 -0
- package/lib/compute.js.map +1 -0
- package/lib/config/env-config.d.ts +4 -0
- package/lib/config/env-config.d.ts.map +1 -0
- package/lib/config/env-config.js +7 -0
- package/lib/config/env-config.js.map +1 -0
- package/lib/docs.config.d.ts +48 -0
- package/lib/docs.config.d.ts.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -0
- package/lib/loaders/search.d.ts +1 -0
- package/lib/loaders/search.d.ts.map +1 -0
- package/lib/module.d.ts +4 -0
- package/lib/module.d.ts.map +1 -0
- package/lib/module.js +11 -0
- package/lib/module.js.map +1 -0
- package/lib/pages/ArticlePage/ArticlePage.d.ts +4 -0
- package/lib/pages/ArticlePage/ArticlePage.d.ts.map +1 -0
- package/lib/pages/ArticlePage/ArticlePage.js +222 -0
- package/lib/pages/ArticlePage/ArticlePage.js.map +1 -0
- package/lib/pages/ArticlePage/index.d.ts +3 -0
- package/lib/pages/ArticlePage/index.d.ts.map +1 -0
- package/lib/pages/ArticlePage/index.js +3 -0
- package/lib/pages/ArticlePage/index.js.map +1 -0
- package/lib/pages/CategoryCollection/CategoryCollection.d.ts +4 -0
- package/lib/pages/CategoryCollection/CategoryCollection.d.ts.map +1 -0
- package/lib/pages/CategoryCollection/CategoryCollection.js +103 -0
- package/lib/pages/CategoryCollection/CategoryCollection.js.map +1 -0
- package/lib/pages/CategoryCollection/index.d.ts +3 -0
- package/lib/pages/CategoryCollection/index.d.ts.map +1 -0
- package/lib/pages/CategoryCollection/index.js +3 -0
- package/lib/pages/CategoryCollection/index.js.map +1 -0
- package/lib/pages/Help/HelpIndex.d.ts +4 -0
- package/lib/pages/Help/HelpIndex.d.ts.map +1 -0
- package/lib/pages/Help/HelpIndex.js +44 -0
- package/lib/pages/Help/HelpIndex.js.map +1 -0
- package/lib/pages/Help/index.d.ts +4 -0
- package/lib/pages/Help/index.d.ts.map +1 -0
- package/lib/pages/Help/index.js +226 -0
- package/lib/pages/Help/index.js.map +1 -0
- package/lib/pages/Landing/index.d.ts +3 -0
- package/lib/pages/Landing/index.d.ts.map +1 -0
- package/lib/pages/Landing/index.js +281 -0
- package/lib/pages/Landing/index.js.map +1 -0
- package/lib/routes.json +2533 -0
- package/lib/seo.d.ts +22 -0
- package/lib/seo.d.ts.map +1 -0
- package/lib/slot-fill/FooterFill.d.ts +3 -0
- package/lib/slot-fill/FooterFill.d.ts.map +1 -0
- package/lib/slot-fill/FooterFill.js +18 -0
- package/lib/slot-fill/FooterFill.js.map +1 -0
- package/lib/slot-fill/LogoFill.d.ts +5 -0
- package/lib/slot-fill/LogoFill.d.ts.map +1 -0
- package/lib/slot-fill/LogoFill.js +74 -0
- package/lib/slot-fill/LogoFill.js.map +1 -0
- package/lib/slot-fill/consts.d.ts +5 -0
- package/lib/slot-fill/consts.d.ts.map +1 -0
- package/lib/slot-fill/consts.js +1 -0
- package/lib/slot-fill/consts.js.map +1 -0
- package/lib/slot-fill/index.d.ts +4 -0
- package/lib/slot-fill/index.d.ts.map +1 -0
- package/lib/templates/assets/images/add-link-frontend.png +0 -0
- package/lib/templates/assets/images/add-package-backend.png +0 -0
- package/lib/templates/assets/images/add-to-backend-module.png +0 -0
- package/lib/templates/assets/images/add-upload-client-frontend.png +0 -0
- package/lib/templates/assets/images/additional-parameters.png +0 -0
- package/lib/templates/assets/images/aeh-implementation.png +0 -0
- package/lib/templates/assets/images/aeh-usage.png +0 -0
- package/lib/templates/assets/images/apollo-client/recommendation_cache_mgmt.png +0 -0
- package/lib/templates/assets/images/app-deploy-new-version/jenkins1.PNG +0 -0
- package/lib/templates/assets/images/app-deploy-new-version/jenkins2.PNG +0 -0
- package/lib/templates/assets/images/auth-wrapper-code.png +0 -0
- package/lib/templates/assets/images/cdebase.png +0 -0
- package/lib/templates/assets/images/cdm-locales-directory.png +0 -0
- package/lib/templates/assets/images/client-settings.png +0 -0
- package/lib/templates/assets/images/codegen_file_update.png +0 -0
- package/lib/templates/assets/images/configuration.png +0 -0
- package/lib/templates/assets/images/copy-plugin.png +0 -0
- package/lib/templates/assets/images/docusaurus.png +0 -0
- package/lib/templates/assets/images/error-link.png +0 -0
- package/lib/templates/assets/images/error-sample.png +0 -0
- package/lib/templates/assets/images/extension copy.png +0 -0
- package/lib/templates/assets/images/extension.png +0 -0
- package/lib/templates/assets/images/graphql/graphql-folder-backend.png +0 -0
- package/lib/templates/assets/images/graphql/graphql-folder-with-gql.png +0 -0
- package/lib/templates/assets/images/i18n-config.png +0 -0
- package/lib/templates/assets/images/image.png +0 -0
- package/lib/templates/assets/images/logo.svg +10 -0
- package/lib/templates/assets/images/logo1.svg +1 -0
- package/lib/templates/assets/images/modify-upload-false-server.png +0 -0
- package/lib/templates/assets/images/navigation-auth-enabled.png +0 -0
- package/lib/templates/assets/images/org-dashboard-navigation.png +0 -0
- package/lib/templates/assets/images/org-navigation.png +0 -0
- package/lib/templates/assets/images/preferences_graphql_type.png +0 -0
- package/lib/templates/assets/images/provider.png +0 -0
- package/lib/templates/assets/images/route-config.png +0 -0
- package/lib/templates/assets/images/service-accounts.png +0 -0
- package/lib/templates/assets/images/source-code/source-code-environments.png +0 -0
- package/lib/templates/assets/images/source-code/source-code-organization.png +0 -0
- package/lib/templates/assets/images/spin-clone-develop-deployment/jenkins-changes.png +0 -0
- package/lib/templates/assets/images/spin-clone-develop-deployment/lerna-changes.png +0 -0
- package/lib/templates/assets/images/spin-clone-develop-deployment/root-package-json-changes.png +0 -0
- package/lib/templates/assets/images/spin-clone-develop-deployment/values-dev-changes.png +0 -0
- package/lib/templates/assets/images/sso-mappers.png +0 -0
- package/lib/templates/assets/images/sso-picture-mapper.png +0 -0
- package/lib/templates/assets/images/sso-settings.png +0 -0
- package/lib/templates/assets/images/timesheet_apollo_cache.png +0 -0
- package/lib/templates/assets/images/timesheet_query.png +0 -0
- package/lib/templates/assets/images/tutorial/docsVersionDropdown.png +0 -0
- package/lib/templates/assets/images/tutorial/localeDropdown.png +0 -0
- package/lib/templates/assets/images/unauthenticated.png +0 -0
- package/lib/templates/assets/images/undraw_docusaurus_mountain.svg +170 -0
- package/lib/templates/assets/images/undraw_docusaurus_react.svg +169 -0
- package/lib/templates/assets/images/undraw_docusaurus_tree.svg +1 -0
- package/lib/templates/assets/images/vite-plugin-config.png +0 -0
- package/lib/templates/content/docs/Generators/Project/generate-fullproject.md +12 -0
- package/lib/templates/content/docs/LLM/Logger.llm.md +194 -0
- package/lib/templates/content/docs/LLM/backend-proxies-services-llm.md +2687 -0
- package/lib/templates/content/docs/LLM/backend-service-llm.md +3384 -0
- package/lib/templates/content/docs/LLM/db_migration_llm.md +954 -0
- package/lib/templates/content/docs/LLM/frontend/REMIX-15.3-upgrade-llm.md +1245 -0
- package/lib/templates/content/docs/LLM/inngest/INNGEST_FUNCTION_DEVELOPMENT_GUIDE_LLM.md +1241 -0
- package/lib/templates/content/docs/LLM/inngest/INNGEST_NAMESPACE_LLM.md +384 -0
- package/lib/templates/content/docs/LLM/llm_workflow_namespace.md +384 -0
- package/lib/templates/content/docs/LLM/organization-components-form-llm.md +1395 -0
- package/lib/templates/content/docs/LLM/page-component-llm.md +173 -0
- package/lib/templates/content/docs/LLM/preferences-settings-llm.md +2781 -0
- package/lib/templates/content/docs/LLM/tailwind-css-llm.md +502 -0
- package/lib/templates/content/docs/UI/SchemaBasedUI.md +334 -0
- package/lib/templates/content/docs/UI/SlotFillComponent.md +334 -0
- package/lib/templates/content/docs/adminide-modules/account/auth0-login.md +31 -0
- package/lib/templates/content/docs/adminide-modules/account/index.md +14 -0
- package/lib/templates/content/docs/adminide-modules/account/keycloak-remix-setup.md +86 -0
- package/lib/templates/content/docs/adminide-modules/account/remix-auth-setup.md +79 -0
- package/lib/templates/content/docs/adminide-modules/account/various-auth-qatest.md +157 -0
- package/lib/templates/content/docs/adminide-modules/api-builders/graphql.md +906 -0
- package/lib/templates/content/docs/adminide-modules/billing/payments/index.md +14 -0
- package/lib/templates/content/docs/adminide-modules/billing/payments/stripe/index.md +14 -0
- package/lib/templates/content/docs/adminide-modules/billing/payments/stripe/settingup-stripe-locally.md +25 -0
- package/lib/templates/content/docs/adminide-modules/billing/tier-config.md +293 -0
- package/lib/templates/content/docs/adminide-modules/connectors/Connector.md +207 -0
- package/lib/templates/content/docs/adminide-modules/file-upload/index.md +16 -0
- package/lib/templates/content/docs/adminide-modules/file-upload/setup.md +435 -0
- package/lib/templates/content/docs/adminide-modules/file-upload/upload-file-using-signed-url.md +161 -0
- package/lib/templates/content/docs/adminide-modules/preferences/AddAdditionalPermissions.md +151 -0
- package/lib/templates/content/docs/adminide-modules/preferences/Configuration.md +241 -0
- package/lib/templates/content/docs/adminide-modules/preferences/Policy-Configuration.md +61 -0
- package/lib/templates/content/docs/adminide-modules/preferences/UI-components/ResourceSettingsLoader.md +319 -0
- package/lib/templates/content/docs/adminide-modules/preferences/contribute_scope_target.md +280 -0
- package/lib/templates/content/docs/adminide-modules/preferences/generate-urii.md +94 -0
- package/lib/templates/content/docs/adminide-modules/preferences/index.md +28 -0
- package/lib/templates/content/docs/adminide-modules/preferences/machine-configuration.md +157 -0
- package/lib/templates/content/docs/adminide-modules/preferences/pageSettings/generateCdecodeUri.md +1289 -0
- package/lib/templates/content/docs/adminide-modules/preferences/pageSettings/migratingFromUseSettings.md +215 -0
- package/lib/templates/content/docs/adminide-modules/preferences/permissions/Roles-Permissions.md +72 -0
- package/lib/templates/content/docs/adminide-modules/preferences/permissions/settingUserPermissions.md +139 -0
- package/lib/templates/content/docs/adminide-modules/preferences/preference-dependency.md +138 -0
- package/lib/templates/content/docs/adminide-modules/preferences/route-based-configuration.md +41 -0
- package/lib/templates/content/docs/adminide-modules/preferences/schema-configuration.md +71 -0
- package/lib/templates/content/docs/adminide-modules/preferences/supported.md +24 -0
- package/lib/templates/content/docs/adminide-modules/preferences/useSettingsLoader.md +248 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/auth-providers.md +1317 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/keycloak-guide.md +543 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/tenant-management/tenant-based-authentication.md +846 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/tenant-management/tenant-management.md +708 -0
- package/lib/templates/content/docs/adminide-modules/project-tools/tenant-management/tenants.md +1117 -0
- package/lib/templates/content/docs/chrome-extension/index.md +14 -0
- package/lib/templates/content/docs/chrome-extension/setup.md +30 -0
- package/lib/templates/content/docs/contributing/adding-package.md +23 -0
- package/lib/templates/content/docs/contributing/adding_new_modules.md +99 -0
- package/lib/templates/content/docs/contributing/architecture-updates.md +19 -0
- package/lib/templates/content/docs/contributing/avoid-using-promises-ui.md +116 -0
- package/lib/templates/content/docs/contributing/coding-guidelines.md +111 -0
- package/lib/templates/content/docs/contributing/do-and-dont.md +42 -0
- package/lib/templates/content/docs/contributing/faq.md +22 -0
- package/lib/templates/content/docs/contributing/folder-setup/browser.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/config.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/containers-server.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/core.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/graphql.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/index.md +30 -0
- package/lib/templates/content/docs/contributing/folder-setup/module.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/server.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/services.md +12 -0
- package/lib/templates/content/docs/contributing/folder-setup/store.md +12 -0
- package/lib/templates/content/docs/contributing/frontend-coding.md +30 -0
- package/lib/templates/content/docs/contributing/git-subtree-sharing.md +73 -0
- package/lib/templates/content/docs/contributing/graphql-subscriptions.md +69 -0
- package/lib/templates/content/docs/contributing/how-to-contribute.md +30 -0
- package/lib/templates/content/docs/contributing/how_to_check_pure_esm.md +29 -0
- package/lib/templates/content/docs/contributing/index.md +60 -0
- package/lib/templates/content/docs/contributing/installation-issues.md +23 -0
- package/lib/templates/content/docs/contributing/keyboard-shortcut.md +131 -0
- package/lib/templates/content/docs/contributing/language/locale-support.md +12 -0
- package/lib/templates/content/docs/contributing/lerna-build-tools.md +516 -0
- package/lib/templates/content/docs/contributing/lerna-yarn-workspaces.md +95 -0
- package/lib/templates/content/docs/contributing/lint-and-formatter.md +20 -0
- package/lib/templates/content/docs/contributing/mobile-setup.md +16 -0
- package/lib/templates/content/docs/contributing/project-setup.md +233 -0
- package/lib/templates/content/docs/contributing/react/index.md +14 -0
- package/lib/templates/content/docs/contributing/react/lazy-component.md +70 -0
- package/lib/templates/content/docs/contributing/run-various-options.md +124 -0
- package/lib/templates/content/docs/contributing/schema-first-graphql-types.md +37 -0
- package/lib/templates/content/docs/contributing/source-code-organization.md +57 -0
- package/lib/templates/content/docs/contributing/staging-docker.md +88 -0
- package/lib/templates/content/docs/contributing/third-party/apollo-client-v3-tutorials.md +28 -0
- package/lib/templates/content/docs/contributing/third-party/index.md +18 -0
- package/lib/templates/content/docs/contributing/typescript-contribution.md +16 -0
- package/lib/templates/content/docs/devops/app-deploy-new-version.md +30 -0
- package/lib/templates/content/docs/devops/index.md +14 -0
- package/lib/templates/content/docs/devops/mobile-jenkins-build.md +40 -0
- package/lib/templates/content/docs/devops/versioning-the-project.md +128 -0
- package/lib/templates/content/docs/error-handler/application-error-handler.md +40 -0
- package/lib/templates/content/docs/error-handler/error-handling.md +26 -0
- package/lib/templates/content/docs/error-handler/index.md +16 -0
- package/lib/templates/content/docs/error-handler/logging-errors.md +14 -0
- package/lib/templates/content/docs/feature-api/copy-operation.md +427 -0
- package/lib/templates/content/docs/feature-api/feature-browser/assets.md +46 -0
- package/lib/templates/content/docs/feature-api/feature-browser/auth-permissions.md +12 -0
- package/lib/templates/content/docs/feature-api/feature-browser/feature.md +131 -0
- package/lib/templates/content/docs/feature-api/feature-browser/index.md +22 -0
- package/lib/templates/content/docs/feature-api/feature-browser/routes-menu.md +110 -0
- package/lib/templates/content/docs/feature-api/feature-browser/routing-convention.md +124 -0
- package/lib/templates/content/docs/feature-api/feature-browser/routing.md +338 -0
- package/lib/templates/content/docs/feature-api/feature-mobile/auth-permissions.md +20 -0
- package/lib/templates/content/docs/feature-api/feature-mobile/feature.md +130 -0
- package/lib/templates/content/docs/feature-api/feature-mobile/index.md +18 -0
- package/lib/templates/content/docs/feature-api/feature-mobile/navigation.md +187 -0
- package/lib/templates/content/docs/feature-api/feature-server/Scheduling.md +44 -0
- package/lib/templates/content/docs/feature-api/feature-server/dataloader.md +320 -0
- package/lib/templates/content/docs/feature-api/feature-server/dependency-injection.md +81 -0
- package/lib/templates/content/docs/feature-api/feature-server/feature.md +65 -0
- package/lib/templates/content/docs/feature-api/feature-server/generic-dataloader.md +135 -0
- package/lib/templates/content/docs/feature-api/feature-server/index.md +40 -0
- package/lib/templates/content/docs/feature-api/feature-server/migration.md +127 -0
- package/lib/templates/content/docs/feature-api/feature-server/mongo-model.md +72 -0
- package/lib/templates/content/docs/feature-api/feature-server/permissions.md +12 -0
- package/lib/templates/content/docs/feature-api/feature-server/policies.md +57 -0
- package/lib/templates/content/docs/feature-api/feature-server/preferences.md +57 -0
- package/lib/templates/content/docs/feature-api/feature-server/repositories.md +114 -0
- package/lib/templates/content/docs/feature-api/feature-server/resolvers.md +126 -0
- package/lib/templates/content/docs/feature-api/feature-server/rules.md +132 -0
- package/lib/templates/content/docs/feature-api/feature-server/schema.md +12 -0
- package/lib/templates/content/docs/feature-api/feature-server/services.md +102 -0
- package/lib/templates/content/docs/feature-api/feature-server/setup-resource-crud.md +359 -0
- package/lib/templates/content/docs/feature-api/index.md +18 -0
- package/lib/templates/content/docs/graphql/apolloClient-mutation.md +94 -0
- package/lib/templates/content/docs/graphql/index.md +14 -0
- package/lib/templates/content/docs/graphql/scalars.md +15 -0
- package/lib/templates/content/docs/help/index.md +14 -0
- package/lib/templates/content/docs/help/intro.md +16 -0
- package/lib/templates/content/docs/intl/ant-design-menu-translation.md +74 -0
- package/lib/templates/content/docs/intl/intl-namespace.md +129 -0
- package/lib/templates/content/docs/intl/vite-plugin-intl.md +87 -0
- package/lib/templates/content/docs/intl/webpack-plugin-intl.md +12 -0
- package/lib/templates/content/docs/intro.md +18 -0
- package/lib/templates/content/docs/knowledge/basic-fullstack.md +238 -0
- package/lib/templates/content/docs/mailing/index.md +14 -0
- package/lib/templates/content/docs/mailing/mailing-template.md +148 -0
- package/lib/templates/content/docs/mobile/App-navigation-generator.md +410 -0
- package/lib/templates/content/docs/mobile/MobileTestCases.md +264 -0
- package/lib/templates/content/docs/mobile/eas-profile-build.md +107 -0
- package/lib/templates/content/docs/mobile/expo-push-notification-setup.md +216 -0
- package/lib/templates/content/docs/mobile/index.md +14 -0
- package/lib/templates/content/docs/mobile/routes.md +83 -0
- package/lib/templates/content/docs/organization/adding-account-context.md +116 -0
- package/lib/templates/content/docs/organization/adding-org-mobile-navigation.md +22 -0
- package/lib/templates/content/docs/organization/adding-org-web-navigation.md +12 -0
- package/lib/templates/content/docs/organization/index.md +20 -0
- package/lib/templates/content/docs/organization/initialization.md +20 -0
- package/lib/templates/content/docs/organization/organization-resource-vs-resource.md +112 -0
- package/lib/templates/content/docs/remix/configuration/component-structure-best-practices.md +152 -0
- package/lib/templates/content/docs/remix/configuration/configurations.md +218 -0
- package/lib/templates/content/docs/remix/configuration/css-import-and-stylesheets.md +142 -0
- package/lib/templates/content/docs/remix/configuration/dont-subcomponent-network.md +166 -0
- package/lib/templates/content/docs/remix/configuration/generated-data-loaders.md +122 -0
- package/lib/templates/content/docs/remix/configuration/generated-resource-loaders.md +257 -0
- package/lib/templates/content/docs/remix/configuration/query-params-generator.md +216 -0
- package/lib/templates/content/docs/remix/configuration/routes-extra-icons.md +103 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-advanced.md +86 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-auth.md +113 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-best-practices.md +55 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-fields.md +79 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-graphql.md +79 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-index.md +112 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-loaders.md +165 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-middleware.md +196 -0
- package/lib/templates/content/docs/remix/configuration/routes-json-overview.md +53 -0
- package/lib/templates/content/docs/remix/data-loaders.md +43 -0
- package/lib/templates/content/docs/remix/devtools/remix-devtools.md +58 -0
- package/lib/templates/content/docs/remix/examples/changes-using-servercode.md +79 -0
- package/lib/templates/content/docs/remix/extra-icons.md +62 -0
- package/lib/templates/content/docs/remix/extra-links.md +65 -0
- package/lib/templates/content/docs/remix/generated-data-loaders.md +114 -0
- package/lib/templates/content/docs/remix/queryParamsGenerator.md +89 -0
- package/lib/templates/content/docs/remix/resources.md +16 -0
- package/lib/templates/content/docs/remix/styles.md +132 -0
- package/lib/templates/content/docs/remix/wiki.md +12 -0
- package/lib/templates/content/docs/security/auth-wrapper/auth-wrapper.md +24 -0
- package/lib/templates/content/docs/security/index.md +18 -0
- package/lib/templates/content/docs/security/secure-button-mobilenative.md +88 -0
- package/lib/templates/content/docs/security/secure-button-web.md +89 -0
- package/lib/templates/content/docs/server-side/account-customization.md +82 -0
- package/lib/templates/content/docs/server-side/apollo/caching.md +164 -0
- package/lib/templates/content/docs/server-side/backend-architecture/FINAL-DECISION.md +209 -0
- package/lib/templates/content/docs/server-side/backend-architecture/TRUE-FINAL-ARCHITECTURE.md +603 -0
- package/lib/templates/content/docs/server-side/backend-architecture/index1.md +0 -0
- package/lib/templates/content/docs/server-side/backend-coding.md +839 -0
- package/lib/templates/content/docs/server-side/e2b/manageing-template.md +197 -0
- package/lib/templates/content/docs/server-side/index.md +14 -0
- package/lib/templates/content/docs/server-side/inngest-functions-module.md +309 -0
- package/lib/templates/content/docs/server-side/listen-stripe-events.md +43 -0
- package/lib/templates/content/docs/server-side/slug-service.md +323 -0
- package/lib/templates/content/docs/tests/index.md +18 -0
- package/lib/templates/content/docs/tests/jest-test-debug-vscode.md +40 -0
- package/lib/templates/content/docs/tests/known-errors.md +116 -0
- package/lib/templates/content/docs/tests/service-test-template.md +118 -0
- package/lib/templates/content/docs/tests/test-setup.md +93 -0
- package/lib/templates/content/docs/xstate.md +23 -0
- package/lib/types.d.ts +37 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/utils/docsNavigation.d.ts +9 -0
- package/lib/utils/docsNavigation.d.ts.map +1 -0
- package/lib/utils/docsNavigation.js +37 -0
- package/lib/utils/docsNavigation.js.map +1 -0
- package/lib/utils/helpCenterUtils.d.ts +26 -0
- package/lib/utils/helpCenterUtils.d.ts.map +1 -0
- package/lib/utils/index.d.ts +3 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/index.js +3 -0
- package/lib/utils/index.js.map +1 -0
- package/lib/utils/markdownLoader.d.ts +36 -0
- package/lib/utils/markdownLoader.d.ts.map +1 -0
- package/lib/utils/markdownLoader.js +2242 -0
- package/lib/utils/markdownLoader.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,1317 @@
|
|
|
1
|
+
# Auth Provider Management System - Comprehensive Documentation
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
1. [Overview](#overview)
|
|
6
|
+
2. [What This Functionality Is About](#what-this-functionality-is-about)
|
|
7
|
+
3. [How to Execute the Functionality](#how-to-execute-the-functionality)
|
|
8
|
+
4. [Implementation Details](#implementation-details)
|
|
9
|
+
5. [State Management](#state-management)
|
|
10
|
+
6. [GraphQL Integration](#graphql-integration)
|
|
11
|
+
7. [Backend Architecture & Inngest Integration](#backend-architecture--inngest-integration)
|
|
12
|
+
8. [Important Notes and Best Practices](#important-notes-and-best-practices)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Overview
|
|
17
|
+
|
|
18
|
+
The Auth Provider Management System enables organizations to configure and manage authentication providers (Keycloak and Auth0) for their tenants. It provides a comprehensive interface for creating, updating, testing, and managing authentication configurations with support for both managed and self-hosted Keycloak instances.
|
|
19
|
+
|
|
20
|
+
**Primary Entry Point:** `AuthProvidersManagement.tsx`
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## What This Functionality Is About
|
|
25
|
+
|
|
26
|
+
### Core Purpose
|
|
27
|
+
|
|
28
|
+
The Auth Provider Management System enables organizations to:
|
|
29
|
+
|
|
30
|
+
1. **Configure Authentication Providers**: Set up Keycloak or Auth0 authentication for tenants
|
|
31
|
+
2. **Manage Provider Settings**: Configure realms, clients, redirect URIs, and identity providers
|
|
32
|
+
3. **Test Credentials**: Verify authentication provider configurations work correctly
|
|
33
|
+
4. **Support Multiple Deployment Types**: Handle both managed and self-hosted Keycloak instances
|
|
34
|
+
5. **Tenant Association**: Link authentication providers to specific tenants within an organization
|
|
35
|
+
|
|
36
|
+
### Key Features
|
|
37
|
+
|
|
38
|
+
- ✅ **Multi-Provider Support**: Keycloak (managed/self-hosted) and Auth0
|
|
39
|
+
- ✅ **Realm Management**: Create and configure Keycloak realms
|
|
40
|
+
- ✅ **Client Configuration**: Manage OAuth2/OIDC clients with redirect URIs
|
|
41
|
+
- ✅ **Identity Provider Integration**: Configure social login providers (Google, GitHub, etc.)
|
|
42
|
+
- ✅ **Credential Testing**: Test authentication provider credentials before saving
|
|
43
|
+
- ✅ **Secret Management**: Secure storage of admin credentials and client secrets
|
|
44
|
+
- ✅ **Environment-Based Configuration**: Associate providers with environment tags
|
|
45
|
+
- ✅ **State Machine Management**: Predictable state transitions using XState
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## How to Execute the Functionality
|
|
50
|
+
|
|
51
|
+
### Accessing the Auth Provider Management
|
|
52
|
+
|
|
53
|
+
1. **Navigate to the Route**: Access via organization route with `orgName` parameter
|
|
54
|
+
2. **Prerequisites**:
|
|
55
|
+
- User must be authenticated
|
|
56
|
+
- User must have appropriate permissions for the organization
|
|
57
|
+
- At least one tenant must exist in the organization
|
|
58
|
+
|
|
59
|
+
### Creating a New Auth Provider
|
|
60
|
+
|
|
61
|
+
1. **Click "Create New Auth Provider" Button**: Located in the header
|
|
62
|
+
2. **Select Tenant**: Choose a tenant from the modal (only tenants without existing providers are recommended)
|
|
63
|
+
3. **Choose Provider Type**: Select Keycloak or Auth0
|
|
64
|
+
4. **Configure Settings**:
|
|
65
|
+
- **Keycloak**: Realm name, redirect URIs, signup settings, identity providers
|
|
66
|
+
- **Auth0**: Domain, client ID, client secret, redirect URI
|
|
67
|
+
5. **Test Credentials** (Optional): Click "Test" to verify configuration
|
|
68
|
+
6. **Submit**: Click "Save" to create the provider
|
|
69
|
+
7. **Result**: Provider is created, modal closes, list refreshes
|
|
70
|
+
|
|
71
|
+
### Viewing Auth Provider Details
|
|
72
|
+
|
|
73
|
+
1. **Expand Provider**: Click on any provider card to expand and view details
|
|
74
|
+
2. **View Configuration**: See realm name, client ID, domain, and other settings
|
|
75
|
+
3. **View Identity Providers**: See configured social login providers (for Keycloak)
|
|
76
|
+
|
|
77
|
+
### Editing an Auth Provider
|
|
78
|
+
|
|
79
|
+
1. **Click "Edit" Button**: Located in the action buttons for each provider
|
|
80
|
+
2. **Modify Settings**: Update realm name, redirect URIs, identity providers, etc.
|
|
81
|
+
3. **Test Credentials** (Optional): Verify changes work
|
|
82
|
+
4. **Submit**: Click "Save" to update
|
|
83
|
+
5. **Result**: Provider is updated, modal closes, list refreshes
|
|
84
|
+
|
|
85
|
+
### Testing Credentials
|
|
86
|
+
|
|
87
|
+
1. **Click "Test" Button**: Located in the action buttons
|
|
88
|
+
2. **Wait for Result**: System attempts to obtain OAuth2 token
|
|
89
|
+
3. **View Result**: Success or error message displayed inline
|
|
90
|
+
4. **Interpret Results**:
|
|
91
|
+
- **Success**: Green notification with token details
|
|
92
|
+
- **Failure**: Red notification with error details
|
|
93
|
+
|
|
94
|
+
### Viewing Configuration Details
|
|
95
|
+
|
|
96
|
+
1. **Click "Configuration" Button**: Opens modal with saved configuration
|
|
97
|
+
2. **View Secrets**: See Realm Name, Client ID, Client Secret, Keycloak URL
|
|
98
|
+
3. **Copy to Clipboard**: Click 📋 button to copy any field
|
|
99
|
+
|
|
100
|
+
### Deleting an Auth Provider
|
|
101
|
+
|
|
102
|
+
1. **Click "Delete" Button**: Located in the action buttons
|
|
103
|
+
2. **Confirm**: Confirm deletion in the modal
|
|
104
|
+
3. **Result**: Provider is deleted, Keycloak realm removed (if managed), secrets cleaned up
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Implementation Details
|
|
109
|
+
|
|
110
|
+
### Component Hierarchy
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
AuthProvidersManagement (Main Container)
|
|
114
|
+
├── Auth Providers List (Collapsible Cards)
|
|
115
|
+
│ ├── Provider Header (Expandable)
|
|
116
|
+
│ ├── Provider Details (Expanded View)
|
|
117
|
+
│ └── Action Buttons (Edit, Test, Delete, Configuration)
|
|
118
|
+
├── Tenant Selection Modal
|
|
119
|
+
│ └── Tenant List with Provider Status
|
|
120
|
+
├── Create Auth Provider Modal
|
|
121
|
+
│ └── AuthProvidersComponent
|
|
122
|
+
│ ├── Tenant Selector (if not hidden)
|
|
123
|
+
│ ├── Provider Type Selector
|
|
124
|
+
│ ├── KeycloakBasicConfigForm
|
|
125
|
+
│ ├── KeycloakIdentityProvidersForm
|
|
126
|
+
│ └── Auth0Form
|
|
127
|
+
├── Edit Auth Provider Modal
|
|
128
|
+
│ └── AuthProvidersComponent (pre-populated)
|
|
129
|
+
└── Configuration Modal (View Saved Details)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Key Components
|
|
133
|
+
|
|
134
|
+
#### 1. AuthProvidersManagement (`AuthProvidersManagement.tsx`)
|
|
135
|
+
|
|
136
|
+
**Purpose**: Main orchestrator component for auth provider management.
|
|
137
|
+
|
|
138
|
+
**Responsibilities**:
|
|
139
|
+
|
|
140
|
+
- Organization context management
|
|
141
|
+
- Tenant list loading
|
|
142
|
+
- Auth provider list management
|
|
143
|
+
- Modal state management
|
|
144
|
+
- Credential testing orchestration
|
|
145
|
+
|
|
146
|
+
**Key Features**:
|
|
147
|
+
|
|
148
|
+
- Fetches tenants to determine organization ID
|
|
149
|
+
- Loads auth providers by organization ID
|
|
150
|
+
- Manages multiple modals (create, edit, config, tenant selection)
|
|
151
|
+
- Handles credential testing with inline results
|
|
152
|
+
- Provides collapsible provider cards
|
|
153
|
+
|
|
154
|
+
**State Management**:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
const [showCreateModal, setShowCreateModal] = useState(false);
|
|
158
|
+
const [showEditModal, setShowEditModal] = useState(false);
|
|
159
|
+
const [showConfigModal, setShowConfigModal] = useState(false);
|
|
160
|
+
const [showTenantSelection, setShowTenantSelection] = useState(false);
|
|
161
|
+
const [expandedProviderId, setExpandedProviderId] = useState<string | null>(null);
|
|
162
|
+
const [testingCredentials, setTestingCredentials] = useState<string | null>(null);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
#### 2. AuthProvidersComponent (`AuthProvidersComponent.tsx`)
|
|
166
|
+
|
|
167
|
+
**Purpose**: Reusable form component for creating and editing auth providers.
|
|
168
|
+
|
|
169
|
+
**Features**:
|
|
170
|
+
|
|
171
|
+
- Multi-step form with XState machine
|
|
172
|
+
- Provider type selection (Keycloak/Auth0)
|
|
173
|
+
- Tenant selection (optional, can be hidden)
|
|
174
|
+
- Dynamic form steps based on provider type
|
|
175
|
+
- Pre-population for edit mode
|
|
176
|
+
|
|
177
|
+
**Form Steps**:
|
|
178
|
+
|
|
179
|
+
1. **Tenant Selection** (if not hidden)
|
|
180
|
+
2. **Provider Type Selection**
|
|
181
|
+
3. **Basic Configuration** (Keycloak realm/Auth0 domain)
|
|
182
|
+
4. **Identity Providers** (Keycloak only)
|
|
183
|
+
5. **Review & Submit**
|
|
184
|
+
|
|
185
|
+
**Key Behaviors**:
|
|
186
|
+
|
|
187
|
+
- Auto-loads existing config when `tenantId` prop is provided
|
|
188
|
+
- Validates required fields before submission
|
|
189
|
+
- Handles both create and update operations
|
|
190
|
+
- Integrates with XState machine for state management
|
|
191
|
+
|
|
192
|
+
#### 3. KeycloakBasicConfigForm (`KeycloakBasicConfigForm.tsx`)
|
|
193
|
+
|
|
194
|
+
**Purpose**: Form for Keycloak basic configuration.
|
|
195
|
+
|
|
196
|
+
**Fields**:
|
|
197
|
+
|
|
198
|
+
- Realm Name (required)
|
|
199
|
+
- Redirect URIs (required, array)
|
|
200
|
+
- Allowed New Users (checkbox)
|
|
201
|
+
- Confirm Email (checkbox)
|
|
202
|
+
- Self-Hosted toggle
|
|
203
|
+
- Self-Hosted Config (domain, admin credentials) - if self-hosted
|
|
204
|
+
|
|
205
|
+
**Validation**:
|
|
206
|
+
|
|
207
|
+
- Realm name must be unique
|
|
208
|
+
- At least one redirect URI required
|
|
209
|
+
- Self-hosted requires domain and admin credentials
|
|
210
|
+
|
|
211
|
+
#### 4. KeycloakIdentityProvidersForm (`KeycloakIdentityProvidersForm.tsx`)
|
|
212
|
+
|
|
213
|
+
**Purpose**: Form for configuring social identity providers.
|
|
214
|
+
|
|
215
|
+
**Supported Providers**:
|
|
216
|
+
|
|
217
|
+
- Google
|
|
218
|
+
- GitHub
|
|
219
|
+
- Facebook
|
|
220
|
+
- Microsoft
|
|
221
|
+
- And more...
|
|
222
|
+
|
|
223
|
+
**Configuration per Provider**:
|
|
224
|
+
|
|
225
|
+
- Client ID
|
|
226
|
+
- Client Secret
|
|
227
|
+
- Enabled/Disabled toggle
|
|
228
|
+
|
|
229
|
+
#### 5. Auth0Form (`Auth0Authentication.tsx`)
|
|
230
|
+
|
|
231
|
+
**Purpose**: Form for Auth0 configuration.
|
|
232
|
+
|
|
233
|
+
**Fields**:
|
|
234
|
+
|
|
235
|
+
- Auth0 Domain (required)
|
|
236
|
+
- Client ID (required)
|
|
237
|
+
- Client Secret (required)
|
|
238
|
+
- Redirect URI (required)
|
|
239
|
+
- Auth0 URL (auto-generated)
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## State Management
|
|
244
|
+
|
|
245
|
+
### XState Machine (`authProvidersMachine.ts`)
|
|
246
|
+
|
|
247
|
+
The auth provider management uses XState for multi-step form state management.
|
|
248
|
+
|
|
249
|
+
#### Machine Context
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
interface AuthProviderMachineContext {
|
|
253
|
+
tenant?: ITenant;
|
|
254
|
+
providerType?: AuthProviderName;
|
|
255
|
+
keycloakConfig?: IKeycloakConfig;
|
|
256
|
+
auth0Config?: IAuth0Config;
|
|
257
|
+
currentStep: StepType;
|
|
258
|
+
hideTenantSelector: boolean;
|
|
259
|
+
authProviderConfig?: IAuthProvider;
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### Machine States
|
|
264
|
+
|
|
265
|
+
1. **tenantSelection**: Selecting tenant (if not hidden)
|
|
266
|
+
2. **providerSelection**: Choosing provider type
|
|
267
|
+
3. **keycloakBasicConfig**: Keycloak basic settings
|
|
268
|
+
4. **keycloakIdentityProviders**: Keycloak social providers
|
|
269
|
+
5. **auth0Config**: Auth0 configuration
|
|
270
|
+
6. **review**: Review before submission
|
|
271
|
+
|
|
272
|
+
#### Key Events
|
|
273
|
+
|
|
274
|
+
- `SET_TENANT`: Set selected tenant
|
|
275
|
+
- `SET_PROVIDER_TYPE`: Set provider type (Keycloak/Auth0)
|
|
276
|
+
- `SET_KEYCLOAK_CONFIG`: Update Keycloak configuration
|
|
277
|
+
- `SET_AUTH0_CONFIG`: Update Auth0 configuration
|
|
278
|
+
- `NEXT_STEP`: Move to next step
|
|
279
|
+
- `PREVIOUS_STEP`: Move to previous step
|
|
280
|
+
- `SET_AUTH_PROVIDER_CONFIG`: Load existing config for editing
|
|
281
|
+
- `SET_HIDE_TENANT_SELECTOR`: Hide tenant selector
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## GraphQL Integration
|
|
286
|
+
|
|
287
|
+
### Queries
|
|
288
|
+
|
|
289
|
+
#### FetchAuthProvidersByOrganizationId
|
|
290
|
+
|
|
291
|
+
```graphql
|
|
292
|
+
query FetchAuthProvidersByOrganizationId($organizationId: ID!) {
|
|
293
|
+
fetchAuthProvidersByOrganizationId(organizationId: $organizationId) {
|
|
294
|
+
id
|
|
295
|
+
provider
|
|
296
|
+
tenant {
|
|
297
|
+
id
|
|
298
|
+
tenantId
|
|
299
|
+
}
|
|
300
|
+
keycloak {
|
|
301
|
+
realmName
|
|
302
|
+
clientId
|
|
303
|
+
redirectUris
|
|
304
|
+
identityProviders {
|
|
305
|
+
key
|
|
306
|
+
enabled
|
|
307
|
+
}
|
|
308
|
+
selfHosted
|
|
309
|
+
selfHostedConfig {
|
|
310
|
+
domain
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
auth0 {
|
|
314
|
+
auth0Domain
|
|
315
|
+
clientId
|
|
316
|
+
auth0Url
|
|
317
|
+
}
|
|
318
|
+
environmentTag {
|
|
319
|
+
id
|
|
320
|
+
name
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### FetchAuthProviderByTenantId
|
|
327
|
+
|
|
328
|
+
```graphql
|
|
329
|
+
query FetchAuthProviderByTenantId($tenantId: ID!) {
|
|
330
|
+
fetchAuthProviderByTenantId(tenantId: $tenantId) {
|
|
331
|
+
...AuthProviderFragment
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Mutations
|
|
337
|
+
|
|
338
|
+
#### CreateAuthProvider
|
|
339
|
+
|
|
340
|
+
```graphql
|
|
341
|
+
mutation CreateAuthProvider($input: AuthProviderInput!) {
|
|
342
|
+
createAuthProvider(input: $input) {
|
|
343
|
+
...AuthProviderFragment
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Input Structure**:
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
{
|
|
352
|
+
tenant: string; // tenantId (UUID string)
|
|
353
|
+
environmentTag: string; // Environment tag ID
|
|
354
|
+
project: string; // Project ID
|
|
355
|
+
organization?: string; // Organization ID (optional)
|
|
356
|
+
provider: AuthProviderName; // 'keycloak' or 'auth0'
|
|
357
|
+
keycloak?: {
|
|
358
|
+
realmName: string;
|
|
359
|
+
redirectUris: string[];
|
|
360
|
+
allowedNewUsers: boolean;
|
|
361
|
+
confirmEmail: boolean;
|
|
362
|
+
identityProviders?: Array<{
|
|
363
|
+
key: string;
|
|
364
|
+
clientId: string;
|
|
365
|
+
clientSecret: string;
|
|
366
|
+
enabled: boolean;
|
|
367
|
+
}>;
|
|
368
|
+
selfHosted: boolean;
|
|
369
|
+
selfHostedConfig?: {
|
|
370
|
+
domain: string;
|
|
371
|
+
adminUsername: string;
|
|
372
|
+
adminPassword: string;
|
|
373
|
+
realmName: string;
|
|
374
|
+
adminClientId: string;
|
|
375
|
+
clientSecret: string;
|
|
376
|
+
};
|
|
377
|
+
authFlow: AuthFlow; // 'pkce' or 'implicit'
|
|
378
|
+
};
|
|
379
|
+
auth0?: {
|
|
380
|
+
clientId: string;
|
|
381
|
+
clientSecret: string;
|
|
382
|
+
redirectUri: string;
|
|
383
|
+
auth0Url: string;
|
|
384
|
+
auth0Domain: string;
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
#### UpdateAuthProvider
|
|
390
|
+
|
|
391
|
+
```graphql
|
|
392
|
+
mutation UpdateAuthProvider($id: ID!, $input: AuthProviderInput!) {
|
|
393
|
+
updateAuthProvider(id: $id, input: $input) {
|
|
394
|
+
...AuthProviderFragment
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
#### DeleteAuthProvider
|
|
400
|
+
|
|
401
|
+
```graphql
|
|
402
|
+
mutation DeleteAuthProvider($id: ID!) {
|
|
403
|
+
deleteAuthProvider(id: $id)
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
#### TestAuthProviderCredentials
|
|
408
|
+
|
|
409
|
+
```graphql
|
|
410
|
+
mutation TestAuthProviderCredentials($authProviderId: ID!) {
|
|
411
|
+
testAuthProviderCredentials(authProviderId: $authProviderId) {
|
|
412
|
+
success
|
|
413
|
+
message
|
|
414
|
+
details
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Apollo Client Configuration
|
|
420
|
+
|
|
421
|
+
- **Fetch Policy**: `network-only` for queries (always fetch fresh data)
|
|
422
|
+
- **Refetch Queries**: Automatic refetch after mutations
|
|
423
|
+
- **Error Handling**: Centralized via `onError` callbacks
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Backend Architecture & Inngest Integration
|
|
428
|
+
|
|
429
|
+
### Overview
|
|
430
|
+
|
|
431
|
+
The Auth Provider Management System uses an **event-driven architecture** with **Inngest** for asynchronous Keycloak configuration. The backend service handles immediate database operations and secret storage, while Inngest functions handle Keycloak realm/client creation and configuration.
|
|
432
|
+
|
|
433
|
+
### Architecture Pattern
|
|
434
|
+
|
|
435
|
+
1. **Service Layer** (`AuthProviderService`): Handles database operations and triggers Inngest events
|
|
436
|
+
2. **Inngest Functions**: Handle Keycloak API operations (realm creation, client configuration, identity providers)
|
|
437
|
+
3. **Secret Management**: Environment service stores sensitive credentials securely
|
|
438
|
+
|
|
439
|
+
### Backend Service Layer
|
|
440
|
+
|
|
441
|
+
#### AuthProviderService (`AuthProviderService.ts`)
|
|
442
|
+
|
|
443
|
+
**Purpose**: Core service for auth provider CRUD operations.
|
|
444
|
+
|
|
445
|
+
**Key Methods**:
|
|
446
|
+
|
|
447
|
+
##### `createAuthProvider(input: IAuthProviderInput)`
|
|
448
|
+
|
|
449
|
+
**Flow**:
|
|
450
|
+
|
|
451
|
+
1. Resolves tenant ID using `defaultTenantIdMapper`
|
|
452
|
+
2. Finds tenant by `tenantId` to get MongoDB `id`
|
|
453
|
+
3. Generates unique `clientId` and `clientSecret` for Keycloak
|
|
454
|
+
4. Stores secrets in environment service (for self-hosted Keycloak or Auth0)
|
|
455
|
+
5. Creates auth provider record in MongoDB
|
|
456
|
+
6. **Triggers Inngest Event**: `AUTH_MGMT_CONFIGURE_KEYCLOAK_SETTINGS_EVENT` (for Keycloak only)
|
|
457
|
+
- **Condition**: Only triggers if `input.provider === AuthProviderName.Keycloak`
|
|
458
|
+
- **Event Sending**:
|
|
459
|
+
```typescript
|
|
460
|
+
await this.inngestClient.send({
|
|
461
|
+
name: WorkflowNamespace.AUTH_MGMT_CONFIGURE_KEYCLOAK_SETTINGS_EVENT,
|
|
462
|
+
data: updatedInput, // Full IAuthProviderInput with generated clientId/clientSecret
|
|
463
|
+
});
|
|
464
|
+
```
|
|
465
|
+
- **Timing**: Event is sent **after** database record is created
|
|
466
|
+
- **Non-blocking**: Service doesn't wait for Inngest function to complete
|
|
467
|
+
7. Returns created auth provider immediately
|
|
468
|
+
|
|
469
|
+
**Inngest Event Payload**:
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
{
|
|
473
|
+
name: 'auth-mgmt/configure-keycloak-settings-trigger',
|
|
474
|
+
data: {
|
|
475
|
+
tenant: string, // tenantId (UUID)
|
|
476
|
+
provider: 'keycloak',
|
|
477
|
+
keycloak: {
|
|
478
|
+
realmName: string,
|
|
479
|
+
clientId: string, // Generated unique ID
|
|
480
|
+
clientSecret: string, // Generated unique secret
|
|
481
|
+
redirectUris: string[],
|
|
482
|
+
allowedNewUsers: boolean,
|
|
483
|
+
confirmEmail: boolean,
|
|
484
|
+
identityProviders: Array<{
|
|
485
|
+
key: string,
|
|
486
|
+
clientId: string,
|
|
487
|
+
clientSecret: string,
|
|
488
|
+
enabled: boolean
|
|
489
|
+
}>,
|
|
490
|
+
selfHosted: boolean,
|
|
491
|
+
selfHostedConfig?: { ... },
|
|
492
|
+
authFlow: 'pkce' | 'implicit'
|
|
493
|
+
},
|
|
494
|
+
environmentTag: string,
|
|
495
|
+
project: string,
|
|
496
|
+
organization?: string
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
**Important**:
|
|
502
|
+
|
|
503
|
+
- Auth0 providers **do not** trigger Inngest events (no Keycloak configuration needed)
|
|
504
|
+
- Event is queued by Inngest and processed asynchronously
|
|
505
|
+
- Service method returns immediately, Keycloak configuration happens in background
|
|
506
|
+
|
|
507
|
+
##### `updateAuthProvider(id: string, input: IAuthProviderInput)`
|
|
508
|
+
|
|
509
|
+
**Flow**:
|
|
510
|
+
|
|
511
|
+
1. Finds existing auth provider
|
|
512
|
+
2. Resolves tenant ID and finds tenant
|
|
513
|
+
3. Updates secrets in environment service (if changed)
|
|
514
|
+
4. **Detects Auth Flow Change**:
|
|
515
|
+
- Compares existing `authFlow` with new `authFlow`
|
|
516
|
+
- Sets `flowChanged` flag if different
|
|
517
|
+
- Stores `previousAuthFlow` for reference
|
|
518
|
+
5. Updates auth provider record in MongoDB
|
|
519
|
+
6. **Triggers Inngest Event**: `AUTH_MGMT_UPDATE_KEYCLOAK_SETTINGS_EVENT` (for Keycloak only)
|
|
520
|
+
- **Condition**: Only triggers if `input.provider === AuthProviderName.Keycloak`
|
|
521
|
+
- **Event Sending**:
|
|
522
|
+
```typescript
|
|
523
|
+
await this.inngestClient.send({
|
|
524
|
+
name: WorkflowNamespace.AUTH_MGMT_UPDATE_KEYCLOAK_SETTINGS_EVENT,
|
|
525
|
+
data: {
|
|
526
|
+
...existingAuthProvider,
|
|
527
|
+
...input,
|
|
528
|
+
flowChanged: boolean,
|
|
529
|
+
previousAuthFlow: AuthFlow,
|
|
530
|
+
},
|
|
531
|
+
});
|
|
532
|
+
```
|
|
533
|
+
- **Timing**: Event is sent **after** database record is updated
|
|
534
|
+
- **Non-blocking**: Service doesn't wait for Inngest function to complete
|
|
535
|
+
7. Returns updated auth provider immediately
|
|
536
|
+
|
|
537
|
+
**Inngest Event Payload**:
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
{
|
|
541
|
+
name: 'auth-mgmt/update-keycloak-settings-trigger',
|
|
542
|
+
data: {
|
|
543
|
+
// Existing auth provider fields
|
|
544
|
+
id: string,
|
|
545
|
+
tenant: string,
|
|
546
|
+
provider: 'keycloak',
|
|
547
|
+
keycloak: {
|
|
548
|
+
// Merged: existing + new values
|
|
549
|
+
realmName: string,
|
|
550
|
+
clientId: string,
|
|
551
|
+
clientSecret: string,
|
|
552
|
+
redirectUris: string[],
|
|
553
|
+
allowedNewUsers: boolean,
|
|
554
|
+
confirmEmail: boolean,
|
|
555
|
+
identityProviders: Array<{ ... }>,
|
|
556
|
+
selfHosted: boolean,
|
|
557
|
+
selfHostedConfig?: { ... },
|
|
558
|
+
authFlow: 'pkce' | 'implicit' // New auth flow
|
|
559
|
+
},
|
|
560
|
+
// Additional metadata
|
|
561
|
+
flowChanged: boolean, // true if auth flow changed
|
|
562
|
+
previousAuthFlow: 'pkce' | 'implicit' // Previous flow value
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
**Important**:
|
|
568
|
+
|
|
569
|
+
- `flowChanged` flag determines if client needs to be deleted/recreated
|
|
570
|
+
- Event contains merged data (existing + new values)
|
|
571
|
+
- Inngest function uses this to determine which steps to execute
|
|
572
|
+
|
|
573
|
+
##### `deleteAuthProvider(id: string)`
|
|
574
|
+
|
|
575
|
+
**Flow**:
|
|
576
|
+
|
|
577
|
+
1. Finds auth provider
|
|
578
|
+
2. **For Managed Keycloak**: Deletes realm via `KeycloakInternalAdminService`
|
|
579
|
+
3. Deletes secrets from environment service
|
|
580
|
+
4. Deletes auth provider record from MongoDB
|
|
581
|
+
5. Returns success boolean
|
|
582
|
+
|
|
583
|
+
**Note**: Self-hosted Keycloak realms are not deleted (user manages them).
|
|
584
|
+
|
|
585
|
+
##### `getAuthProviderByTenantId(tenantId: string)`
|
|
586
|
+
|
|
587
|
+
**Flow**:
|
|
588
|
+
|
|
589
|
+
1. Resolves tenant ID and finds tenant
|
|
590
|
+
2. Finds auth provider by tenant MongoDB `id`
|
|
591
|
+
3. Fetches secrets from environment service
|
|
592
|
+
4. **For Keycloak**: Fetches identity providers and client secret from Keycloak API
|
|
593
|
+
5. Formats response with all secrets merged
|
|
594
|
+
6. Returns formatted auth provider
|
|
595
|
+
|
|
596
|
+
**Secret Fetching**:
|
|
597
|
+
|
|
598
|
+
- Self-hosted Keycloak: Uses `KeycloakTenantAdminService` with admin credentials
|
|
599
|
+
- Managed Keycloak: Uses `KeycloakInternalAdminService`
|
|
600
|
+
- Auth0: Fetches from environment service
|
|
601
|
+
|
|
602
|
+
##### `testAuthProviderCredentials(authProviderId: string)`
|
|
603
|
+
|
|
604
|
+
**Purpose**: Tests authentication provider credentials by attempting OAuth2 token exchange.
|
|
605
|
+
|
|
606
|
+
**Flow for Keycloak**:
|
|
607
|
+
|
|
608
|
+
1. Fetches auth provider
|
|
609
|
+
2. Determines Keycloak URL (managed vs self-hosted)
|
|
610
|
+
3. Fetches client secret from Keycloak API
|
|
611
|
+
4. Calls token endpoint: `POST /realms/{realm}/protocol/openid-connect/token`
|
|
612
|
+
5. Uses `client_credentials` grant type
|
|
613
|
+
6. Returns success/failure with details
|
|
614
|
+
|
|
615
|
+
**Flow for Auth0**:
|
|
616
|
+
|
|
617
|
+
1. Fetches auth provider
|
|
618
|
+
2. Fetches client secret from environment service
|
|
619
|
+
3. Calls token endpoint: `POST https://{domain}/oauth/token`
|
|
620
|
+
4. Uses `client_credentials` grant type with audience
|
|
621
|
+
5. Returns success/failure with details
|
|
622
|
+
|
|
623
|
+
#### Secret Management
|
|
624
|
+
|
|
625
|
+
**Environment Service Integration**:
|
|
626
|
+
|
|
627
|
+
Secrets are stored in environment service with keys:
|
|
628
|
+
|
|
629
|
+
- `KeycloakAdminUsername`: Admin username (self-hosted)
|
|
630
|
+
- `KeycloakAdminPassword`: Admin password (self-hosted)
|
|
631
|
+
- `KeycloakAdminClientSecret`: Admin client secret (self-hosted)
|
|
632
|
+
- `Auth0ClientSecret`: Auth0 client secret
|
|
633
|
+
|
|
634
|
+
**Secret Keys Structure**:
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
{
|
|
638
|
+
tenantId: string; // MongoDB ObjectId
|
|
639
|
+
environmentTag: string; // Environment tag ID
|
|
640
|
+
projectId: string; // Project ID
|
|
641
|
+
}
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Inngest Event-Driven Workflow
|
|
645
|
+
|
|
646
|
+
#### Overview
|
|
647
|
+
|
|
648
|
+
Inngest handles all asynchronous Keycloak API operations. When an auth provider is created or updated, the service immediately returns success to the frontend, while Inngest processes the Keycloak configuration in the background. This ensures fast user experience while handling potentially slow Keycloak API calls.
|
|
649
|
+
|
|
650
|
+
#### Event Namespace
|
|
651
|
+
|
|
652
|
+
**Trigger Events** (what functions listen for):
|
|
653
|
+
|
|
654
|
+
- `AUTH_MGMT_CONFIGURE_KEYCLOAK_SETTINGS_EVENT`: Configure new Keycloak provider
|
|
655
|
+
- `AUTH_MGMT_UPDATE_KEYCLOAK_SETTINGS_EVENT`: Update existing Keycloak provider
|
|
656
|
+
|
|
657
|
+
**Function IDs**:
|
|
658
|
+
|
|
659
|
+
- `AUTH_MGMT_CONFIGURE_KEYCLOAK_SETTINGS`: Function for initial configuration
|
|
660
|
+
- `AUTH_MGMT_UPDATE_KEYCLOAK_SETTINGS`: Function for updates
|
|
661
|
+
|
|
662
|
+
**Event Payload Structure**:
|
|
663
|
+
|
|
664
|
+
```typescript
|
|
665
|
+
// For CREATE
|
|
666
|
+
{
|
|
667
|
+
name: 'auth-mgmt/configure-keycloak-settings-trigger',
|
|
668
|
+
data: IAuthProviderInput {
|
|
669
|
+
tenant: string,
|
|
670
|
+
provider: 'keycloak',
|
|
671
|
+
keycloak: {
|
|
672
|
+
realmName: string,
|
|
673
|
+
clientId: string,
|
|
674
|
+
clientSecret: string,
|
|
675
|
+
redirectUris: string[],
|
|
676
|
+
allowedNewUsers: boolean,
|
|
677
|
+
confirmEmail: boolean,
|
|
678
|
+
identityProviders: Array<{
|
|
679
|
+
key: string, // 'google', 'github', etc.
|
|
680
|
+
clientId: string,
|
|
681
|
+
clientSecret: string,
|
|
682
|
+
enabled: boolean
|
|
683
|
+
}>,
|
|
684
|
+
selfHosted: boolean,
|
|
685
|
+
selfHostedConfig?: {
|
|
686
|
+
domain: string,
|
|
687
|
+
adminUsername: string,
|
|
688
|
+
adminPassword: string,
|
|
689
|
+
realmName: string,
|
|
690
|
+
adminClientId: string,
|
|
691
|
+
clientSecret: string
|
|
692
|
+
},
|
|
693
|
+
authFlow: 'pkce' | 'implicit'
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// For UPDATE
|
|
699
|
+
{
|
|
700
|
+
name: 'auth-mgmt/update-keycloak-settings-trigger',
|
|
701
|
+
data: IAuthProviderInput & {
|
|
702
|
+
flowChanged?: boolean,
|
|
703
|
+
previousAuthFlow?: AuthFlow
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
#### Inngest Functions
|
|
709
|
+
|
|
710
|
+
##### 1. `configureKeycloakAuthSettingFunction`
|
|
711
|
+
|
|
712
|
+
**Purpose**: Creates Keycloak realm and client for new auth provider.
|
|
713
|
+
|
|
714
|
+
**Trigger**: `AUTH_MGMT_CONFIGURE_KEYCLOAK_SETTINGS_EVENT`
|
|
715
|
+
|
|
716
|
+
**Function Registration**:
|
|
717
|
+
|
|
718
|
+
```typescript
|
|
719
|
+
inngest.createFunction(
|
|
720
|
+
{ id: 'auth-mgmt-configure-keycloak-settings' },
|
|
721
|
+
{ event: 'auth-mgmt/configure-keycloak-settings-trigger' },
|
|
722
|
+
async ({ event, step }) => { ... }
|
|
723
|
+
)
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
**Detailed Workflow Steps**:
|
|
727
|
+
|
|
728
|
+
1. **Data Extraction & Preparation**
|
|
729
|
+
- Extracts `keycloakConfiguration` from event data
|
|
730
|
+
- Parses realm name, client ID, client secret, redirect URIs
|
|
731
|
+
- Extracts identity providers array
|
|
732
|
+
- Determines if self-hosted or managed
|
|
733
|
+
|
|
734
|
+
2. **Web Origins Extraction** (Before any Keycloak calls)
|
|
735
|
+
- Iterates through `redirectUris` array
|
|
736
|
+
- For each redirect URI:
|
|
737
|
+
- Parses URL using `new URL(redirectUri)`
|
|
738
|
+
- Extracts `origin` (protocol + domain + port)
|
|
739
|
+
- Adds to `webOrigins` array (deduplicated)
|
|
740
|
+
- **Purpose**: Web origins are required for CORS configuration in Keycloak
|
|
741
|
+
- **Example**: `https://example.com/callback` → `https://example.com`
|
|
742
|
+
|
|
743
|
+
3. **Step: `create-realm-and-client`** (Managed Keycloak only)
|
|
744
|
+
- **Condition**: Only executes if `selfHosted === false`
|
|
745
|
+
- **Operation**: Calls `KeycloakInternalAdminService.Instance.createRealmAndClient()`
|
|
746
|
+
- **Parameters**:
|
|
747
|
+
```typescript
|
|
748
|
+
{
|
|
749
|
+
realm: realmName, // Realm name
|
|
750
|
+
clientId: clientId, // Generated client ID
|
|
751
|
+
clientSecret: clientSecret, // Generated client secret
|
|
752
|
+
redirectUris: redirectUris || [], // Array of redirect URIs
|
|
753
|
+
webOrigins: webOrigins, // Extracted web origins
|
|
754
|
+
signupSetting: {
|
|
755
|
+
allowNewUsers: allowedNewUsers, // Boolean
|
|
756
|
+
confirmEmail: confirmEmail // Boolean
|
|
757
|
+
},
|
|
758
|
+
authFlow: authFlow || AuthFlow.Pkce // 'pkce' or 'implicit'
|
|
759
|
+
}
|
|
760
|
+
```
|
|
761
|
+
- **What Happens**:
|
|
762
|
+
- Creates new Keycloak realm with specified name
|
|
763
|
+
- Creates OAuth2/OIDC client within the realm
|
|
764
|
+
- Configures client with redirect URIs and web origins
|
|
765
|
+
- Sets up signup settings (user registration, email confirmation)
|
|
766
|
+
- Configures authentication flow (PKCE or Implicit)
|
|
767
|
+
- Assigns realm management roles to the client
|
|
768
|
+
- **Error Handling**: If this step fails, entire function fails (realm creation is critical)
|
|
769
|
+
|
|
770
|
+
4. **Step: `configure-identity-providers`** (Both managed and self-hosted)
|
|
771
|
+
- **Condition**: Executes if `identityProviders?.length > 0`
|
|
772
|
+
- **Process**: Iterates through each identity provider in the array
|
|
773
|
+
- **For Each Provider**:
|
|
774
|
+
- **Managed Keycloak**:
|
|
775
|
+
- Uses `KeycloakInternalAdminService.Instance.configureIdentityProviderInternal()`
|
|
776
|
+
- **Parameters**:
|
|
777
|
+
```typescript
|
|
778
|
+
{
|
|
779
|
+
realm: realmName,
|
|
780
|
+
idpAlias: provider.key, // 'google', 'github', etc.
|
|
781
|
+
providerId: provider.key, // Same as alias
|
|
782
|
+
enabled: provider.enabled, // Boolean
|
|
783
|
+
identityProvidersConfig: {
|
|
784
|
+
clientId: provider.clientId,
|
|
785
|
+
clientSecret: provider.clientSecret
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
```
|
|
789
|
+
- **Self-Hosted Keycloak**:
|
|
790
|
+
- Creates `KeycloakTenantAdminService` instance from self-hosted config
|
|
791
|
+
- Uses admin credentials from `selfHostedConfig`
|
|
792
|
+
- Calls `configureIdentityProvider()` with same parameters
|
|
793
|
+
- **Service Creation**:
|
|
794
|
+
```typescript
|
|
795
|
+
KeycloakTenantAdminService.fromSelfHostedConfig({
|
|
796
|
+
domain: selfHostedConfig.domain,
|
|
797
|
+
adminClientId: selfHostedConfig.adminClientId,
|
|
798
|
+
adminUsername: selfHostedConfig.adminUsername,
|
|
799
|
+
adminPassword: selfHostedConfig.adminPassword,
|
|
800
|
+
realmName: selfHostedConfig.realmName,
|
|
801
|
+
clientSecret: selfHostedConfig.clientSecret,
|
|
802
|
+
});
|
|
803
|
+
```
|
|
804
|
+
- **Error Handling**:
|
|
805
|
+
- Individual provider failures are **logged but don't stop the process**
|
|
806
|
+
- Each provider is processed independently
|
|
807
|
+
- Errors logged as: `❌ Failed to process provider {key}: {error}`
|
|
808
|
+
- Success logged as: `✅ Provider processed: {key} (enabled: {enabled})`
|
|
809
|
+
- **Result**: All enabled identity providers are configured in Keycloak
|
|
810
|
+
|
|
811
|
+
**Return Value**:
|
|
812
|
+
|
|
813
|
+
```typescript
|
|
814
|
+
{ status: 'success', realm: realmName }
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
**Important Notes**:
|
|
818
|
+
|
|
819
|
+
- Self-hosted Keycloak **skips** realm/client creation (assumes realm exists)
|
|
820
|
+
- Identity provider configuration happens for both managed and self-hosted
|
|
821
|
+
- Web origins are automatically derived from redirect URIs
|
|
822
|
+
- Individual identity provider failures don't fail the entire operation
|
|
823
|
+
|
|
824
|
+
##### 2. `updateKeycloakAuthSettingFunction`
|
|
825
|
+
|
|
826
|
+
**Purpose**: Updates existing Keycloak configuration.
|
|
827
|
+
|
|
828
|
+
**Trigger**: `AUTH_MGMT_UPDATE_KEYCLOAK_SETTINGS_EVENT`
|
|
829
|
+
|
|
830
|
+
**Function Registration**:
|
|
831
|
+
|
|
832
|
+
```typescript
|
|
833
|
+
inngest.createFunction(
|
|
834
|
+
{ id: 'auth-mgmt-update-keycloak-settings' },
|
|
835
|
+
{ event: 'auth-mgmt/update-keycloak-settings-trigger' },
|
|
836
|
+
async ({ event, step }) => { ... }
|
|
837
|
+
)
|
|
838
|
+
```
|
|
839
|
+
|
|
840
|
+
**Detailed Workflow Steps**:
|
|
841
|
+
|
|
842
|
+
1. **Data Extraction & Preparation**
|
|
843
|
+
- Extracts `keycloakConfiguration` from event data
|
|
844
|
+
- Checks `flowChanged` flag (indicates if auth flow changed)
|
|
845
|
+
- Extracts `previousAuthFlow` if available
|
|
846
|
+
- Determines new auth flow: `authFlow || AuthFlow.Pkce`
|
|
847
|
+
|
|
848
|
+
2. **Web Origins Extraction** (Same as configure function)
|
|
849
|
+
- Extracts web origins from redirect URIs
|
|
850
|
+
- Used for client updates
|
|
851
|
+
|
|
852
|
+
3. **Service Instance Creation** (Self-hosted only)
|
|
853
|
+
- If `selfHosted === true`:
|
|
854
|
+
- Creates `KeycloakTenantAdminService` instance
|
|
855
|
+
- Uses credentials from `selfHostedConfig`
|
|
856
|
+
- Instance used for all self-hosted operations
|
|
857
|
+
|
|
858
|
+
4. **Step: `update-realm-settings`** (Conditional)
|
|
859
|
+
- **Condition**: Executes if signup settings have non-null values
|
|
860
|
+
- **Signup Settings**:
|
|
861
|
+
```typescript
|
|
862
|
+
{
|
|
863
|
+
allowNewUsers: allowedNewUsers, // Boolean or null
|
|
864
|
+
confirmEmail: confirmEmail // Boolean or null
|
|
865
|
+
}
|
|
866
|
+
```
|
|
867
|
+
- **Managed Keycloak**:
|
|
868
|
+
- Calls `KeycloakInternalAdminService.Instance.updateRealmSettings()`
|
|
869
|
+
- **Parameters**: `{ realm: realmName, signupSettings }`
|
|
870
|
+
- **Self-Hosted Keycloak**:
|
|
871
|
+
- Calls `KeycloakTenantAdminServiceInstance.updateRealmSettings()`
|
|
872
|
+
- **Parameters**: `{ realm: selfHostedConfig.realmName, signupSettings }`
|
|
873
|
+
- **What Happens**: Updates realm-level settings for user registration and email confirmation
|
|
874
|
+
- **Error Handling**: Throws error if update fails (critical operation)
|
|
875
|
+
|
|
876
|
+
5. **Step: `delete-and-recreate-client`** (Conditional - Auth Flow Changed)
|
|
877
|
+
- **Condition**: Executes if:
|
|
878
|
+
- `authFlowChanged === true`
|
|
879
|
+
- `selfHosted === false` (only for managed Keycloak)
|
|
880
|
+
- `clientId` exists
|
|
881
|
+
- **Why**: Auth flow (PKCE vs Implicit) requires different client configuration. Cannot be changed on existing client.
|
|
882
|
+
- **Process**:
|
|
883
|
+
1. **Delete Existing Client**:
|
|
884
|
+
- Calls `KeycloakInternalAdminService.Instance.deleteClientInternal(realmName, clientId)`
|
|
885
|
+
- Removes old client with old flow configuration
|
|
886
|
+
2. **Create New Client**:
|
|
887
|
+
- Calls `KeycloakInternalAdminService.Instance.createClientAndAssignRealmManagementRoles()`
|
|
888
|
+
- **Parameters**:
|
|
889
|
+
```typescript
|
|
890
|
+
{
|
|
891
|
+
realm: realmName,
|
|
892
|
+
clientId: clientId, // Same client ID
|
|
893
|
+
clientSecret: clientSecret, // Same client secret
|
|
894
|
+
redirectUris: redirectUris || [],
|
|
895
|
+
webOrigins: webOrigins,
|
|
896
|
+
authFlow: newAuthFlow // New flow (PKCE or Implicit)
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
- Creates new client with new flow configuration
|
|
900
|
+
- Assigns realm management roles
|
|
901
|
+
- **Error Handling**: Throws error if deletion or creation fails
|
|
902
|
+
|
|
903
|
+
6. **Step: `update-client-settings`** (Conditional - Auth Flow Unchanged)
|
|
904
|
+
- **Condition**: Executes if:
|
|
905
|
+
- `authFlowChanged === false` (flow didn't change)
|
|
906
|
+
- `redirectUris?.length > 0 || webOrigins.length > 0` (has redirect URIs)
|
|
907
|
+
- `clientId` exists
|
|
908
|
+
- `selfHosted === false` (only for managed Keycloak)
|
|
909
|
+
- **Operation**: Calls `KeycloakInternalAdminService.Instance.updateClientInternal()`
|
|
910
|
+
- **Parameters**:
|
|
911
|
+
```typescript
|
|
912
|
+
{
|
|
913
|
+
realm: realmName,
|
|
914
|
+
clientId: clientId,
|
|
915
|
+
redirectUris: redirectUris || [],
|
|
916
|
+
webOrigins: webOrigins
|
|
917
|
+
}
|
|
918
|
+
```
|
|
919
|
+
- **What Happens**: Updates existing client's redirect URIs and web origins
|
|
920
|
+
- **Error Handling**: Throws error if update fails
|
|
921
|
+
|
|
922
|
+
7. **Step: `configure-identity-providers`** (Always executes if providers exist)
|
|
923
|
+
- **Process**: Iterates through `identityProviders` array
|
|
924
|
+
- **For Each Provider**:
|
|
925
|
+
- **Managed Keycloak**:
|
|
926
|
+
- Uses `KeycloakInternalAdminService.Instance.configureIdentityProviderInternal()`
|
|
927
|
+
- Updates or creates identity provider configuration
|
|
928
|
+
- **Self-Hosted Keycloak**:
|
|
929
|
+
- Uses `KeycloakTenantAdminServiceInstance.configureIdentityProviderInternal()`
|
|
930
|
+
- Updates or creates identity provider configuration
|
|
931
|
+
- **Parameters** (same as configure function):
|
|
932
|
+
```typescript
|
|
933
|
+
{
|
|
934
|
+
realm: realmName,
|
|
935
|
+
idpAlias: provider.key,
|
|
936
|
+
providerId: provider.key,
|
|
937
|
+
enabled: provider.enabled,
|
|
938
|
+
identityProvidersConfig: {
|
|
939
|
+
clientId: provider.clientId,
|
|
940
|
+
clientSecret: provider.clientSecret
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
```
|
|
944
|
+
- **Error Handling**:
|
|
945
|
+
- **Important**: Unlike configure function, errors here **throw and stop the process**
|
|
946
|
+
- Each provider error throws: `new Error('Failed to process provider', err)`
|
|
947
|
+
- This ensures all identity providers are successfully updated
|
|
948
|
+
|
|
949
|
+
**Return Value**:
|
|
950
|
+
|
|
951
|
+
```typescript
|
|
952
|
+
{ status: 'success', realm: realmName }
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
**Important Notes**:
|
|
956
|
+
|
|
957
|
+
- Auth flow changes require client deletion and recreation (cannot be updated in place)
|
|
958
|
+
- Self-hosted Keycloak skips client operations (user manages clients)
|
|
959
|
+
- Identity provider updates are atomic (all must succeed)
|
|
960
|
+
- Realm settings update is optional (only if values provided)
|
|
961
|
+
|
|
962
|
+
#### Inngest Function Registration
|
|
963
|
+
|
|
964
|
+
**Location**: `packages-modules/user-auth0/server/src/modules/user-auth/inngest/functions.ts`
|
|
965
|
+
|
|
966
|
+
**Registration**:
|
|
967
|
+
|
|
968
|
+
```typescript
|
|
969
|
+
export const inngestFunctionsFactory = (args: { container: Container; inngest: Inngest }) => [
|
|
970
|
+
configureKeycloakAuthSettingFunction(args.inngest),
|
|
971
|
+
updateKeycloakAuthSettingFunction(args.inngest),
|
|
972
|
+
// ... other functions
|
|
973
|
+
];
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
**When Functions Execute**:
|
|
977
|
+
|
|
978
|
+
- Functions are registered at server startup
|
|
979
|
+
- Inngest listens for events matching the function's event pattern
|
|
980
|
+
- When service sends event, Inngest queues the function execution
|
|
981
|
+
- Functions execute asynchronously in background
|
|
982
|
+
|
|
983
|
+
#### Error Handling in Inngest Functions
|
|
984
|
+
|
|
985
|
+
**Configure Function**:
|
|
986
|
+
|
|
987
|
+
- Realm/client creation failure: **Function fails** (critical)
|
|
988
|
+
- Identity provider failure: **Logged, continues** (non-critical)
|
|
989
|
+
|
|
990
|
+
**Update Function**:
|
|
991
|
+
|
|
992
|
+
- Realm settings failure: **Function fails** (critical)
|
|
993
|
+
- Client deletion/recreation failure: **Function fails** (critical)
|
|
994
|
+
- Client update failure: **Function fails** (critical)
|
|
995
|
+
- Identity provider failure: **Function fails** (all must succeed)
|
|
996
|
+
|
|
997
|
+
**Retry Behavior**:
|
|
998
|
+
|
|
999
|
+
- Inngest automatically retries failed functions
|
|
1000
|
+
- Retry strategy: Exponential backoff
|
|
1001
|
+
- Maximum retries: Configurable in Inngest dashboard
|
|
1002
|
+
|
|
1003
|
+
#### Performance Considerations
|
|
1004
|
+
|
|
1005
|
+
**Async Processing**:
|
|
1006
|
+
|
|
1007
|
+
- Service methods return immediately after triggering Inngest events
|
|
1008
|
+
- Keycloak API operations happen asynchronously
|
|
1009
|
+
- Frontend doesn't wait for Keycloak configuration to complete
|
|
1010
|
+
|
|
1011
|
+
**Step Isolation**:
|
|
1012
|
+
|
|
1013
|
+
- Each `step.run()` is isolated and can be retried independently
|
|
1014
|
+
- Inngest tracks step execution state
|
|
1015
|
+
- Failed steps can be retried without re-running successful steps
|
|
1016
|
+
|
|
1017
|
+
**Idempotency**:
|
|
1018
|
+
|
|
1019
|
+
- Functions are designed to be safely retried
|
|
1020
|
+
- Identity provider configuration is idempotent (can be called multiple times)
|
|
1021
|
+
- Client creation checks for existing client before creating
|
|
1022
|
+
|
|
1023
|
+
### Complete Data Flow
|
|
1024
|
+
|
|
1025
|
+
#### Creating an Auth Provider
|
|
1026
|
+
|
|
1027
|
+
```
|
|
1028
|
+
1. Frontend: User submits auth provider form
|
|
1029
|
+
↓
|
|
1030
|
+
2. GraphQL Mutation: createAuthProvider(input)
|
|
1031
|
+
↓
|
|
1032
|
+
3. AuthProviderService.createAuthProvider()
|
|
1033
|
+
├── Resolves tenant ID
|
|
1034
|
+
├── Generates clientId/clientSecret
|
|
1035
|
+
├── Stores secrets in environment service
|
|
1036
|
+
├── Creates auth provider in MongoDB
|
|
1037
|
+
└── Triggers Inngest Event: AUTH_MGMT_CONFIGURE_KEYCLOAK_SETTINGS_EVENT
|
|
1038
|
+
↓
|
|
1039
|
+
4. Returns auth provider to frontend
|
|
1040
|
+
↓
|
|
1041
|
+
5. Inngest Function: configureKeycloakAuthSettingFunction
|
|
1042
|
+
├── Step 1: Create realm and client (managed only)
|
|
1043
|
+
└── Step 2: Configure identity providers
|
|
1044
|
+
↓
|
|
1045
|
+
6. Keycloak realm and client created
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
#### Updating an Auth Provider
|
|
1049
|
+
|
|
1050
|
+
```
|
|
1051
|
+
1. Frontend: User updates auth provider form
|
|
1052
|
+
↓
|
|
1053
|
+
2. GraphQL Mutation: updateAuthProvider(id, input)
|
|
1054
|
+
↓
|
|
1055
|
+
3. AuthProviderService.updateAuthProvider()
|
|
1056
|
+
├── Updates secrets in environment service
|
|
1057
|
+
├── Updates auth provider in MongoDB
|
|
1058
|
+
└── Triggers Inngest Event: AUTH_MGMT_UPDATE_KEYCLOAK_SETTINGS_EVENT
|
|
1059
|
+
↓
|
|
1060
|
+
4. Returns updated auth provider to frontend
|
|
1061
|
+
↓
|
|
1062
|
+
5. Inngest Function: updateKeycloakAuthSettingFunction
|
|
1063
|
+
├── Step 1: Update realm settings
|
|
1064
|
+
├── Step 2: Delete/recreate client (if flow changed)
|
|
1065
|
+
├── Step 3: Update client settings (if flow unchanged)
|
|
1066
|
+
└── Step 4: Configure identity providers
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
#### Testing Credentials
|
|
1070
|
+
|
|
1071
|
+
```
|
|
1072
|
+
1. Frontend: User clicks "Test" button
|
|
1073
|
+
↓
|
|
1074
|
+
2. GraphQL Mutation: testAuthProviderCredentials(authProviderId)
|
|
1075
|
+
↓
|
|
1076
|
+
3. AuthProviderService.testAuthProviderCredentials()
|
|
1077
|
+
├── Fetches auth provider
|
|
1078
|
+
├── Fetches client secret (from Keycloak API or environment)
|
|
1079
|
+
├── Calls OAuth2 token endpoint
|
|
1080
|
+
└── Returns success/failure with details
|
|
1081
|
+
↓
|
|
1082
|
+
4. Frontend displays result inline
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
### Keycloak Integration
|
|
1086
|
+
|
|
1087
|
+
#### Managed Keycloak
|
|
1088
|
+
|
|
1089
|
+
**Service**: `KeycloakInternalAdminService.Instance`
|
|
1090
|
+
|
|
1091
|
+
**Operations**:
|
|
1092
|
+
|
|
1093
|
+
- `createRealmAndClient()`: Creates realm and OAuth2 client
|
|
1094
|
+
- `updateRealmSettings()`: Updates realm signup settings
|
|
1095
|
+
- `updateClientInternal()`: Updates client redirect URIs
|
|
1096
|
+
- `deleteClientInternal()`: Deletes client
|
|
1097
|
+
- `configureIdentityProviderInternal()`: Configures social login providers
|
|
1098
|
+
- `getClientSecretInternal()`: Fetches client secret
|
|
1099
|
+
- `deleteRealmInternal()`: Deletes entire realm
|
|
1100
|
+
|
|
1101
|
+
#### Self-Hosted Keycloak
|
|
1102
|
+
|
|
1103
|
+
**Service**: `KeycloakTenantAdminService.fromSelfHostedConfig()`
|
|
1104
|
+
|
|
1105
|
+
**Configuration**:
|
|
1106
|
+
|
|
1107
|
+
- Domain: Keycloak server URL
|
|
1108
|
+
- Admin credentials: Username, password, client ID, client secret
|
|
1109
|
+
- Realm name: Target realm
|
|
1110
|
+
|
|
1111
|
+
**Operations**:
|
|
1112
|
+
|
|
1113
|
+
- `configureIdentityProvider()`: Configures social login providers
|
|
1114
|
+
- `updateRealmSettings()`: Updates realm settings
|
|
1115
|
+
- `getClientSecret()`: Fetches client secret
|
|
1116
|
+
|
|
1117
|
+
### Auth Flow Types
|
|
1118
|
+
|
|
1119
|
+
**PKCE (Authorization Code Flow with PKCE)**:
|
|
1120
|
+
|
|
1121
|
+
- Recommended for web and mobile apps
|
|
1122
|
+
- More secure than implicit flow
|
|
1123
|
+
- Uses code verifier/challenge
|
|
1124
|
+
|
|
1125
|
+
**Implicit Flow**:
|
|
1126
|
+
|
|
1127
|
+
- Legacy flow
|
|
1128
|
+
- Less secure
|
|
1129
|
+
- Direct token return
|
|
1130
|
+
|
|
1131
|
+
**Flow Change Handling**:
|
|
1132
|
+
|
|
1133
|
+
- When auth flow changes, old client is deleted and new one created
|
|
1134
|
+
- This ensures proper configuration for the new flow type
|
|
1135
|
+
|
|
1136
|
+
### Error Handling
|
|
1137
|
+
|
|
1138
|
+
#### Service Layer Errors
|
|
1139
|
+
|
|
1140
|
+
- **Database Errors**: Thrown immediately
|
|
1141
|
+
- **Keycloak API Errors**: Logged, may not fail entire operation
|
|
1142
|
+
- **Secret Storage Errors**: Logged, operation continues
|
|
1143
|
+
|
|
1144
|
+
#### Inngest Function Errors
|
|
1145
|
+
|
|
1146
|
+
- **Realm Creation Failures**: Logged, operation fails
|
|
1147
|
+
- **Identity Provider Failures**: Logged individually, doesn't stop other providers
|
|
1148
|
+
- **Client Update Failures**: Logged, operation fails
|
|
1149
|
+
|
|
1150
|
+
### Security Considerations
|
|
1151
|
+
|
|
1152
|
+
1. **Secret Storage**: All secrets stored in environment service, not in database
|
|
1153
|
+
2. **Client Secret Generation**: Unique secrets generated for each provider
|
|
1154
|
+
3. **Admin Credentials**: Only stored for self-hosted Keycloak, in environment service
|
|
1155
|
+
4. **Token Testing**: Uses OAuth2 client credentials flow (secure)
|
|
1156
|
+
5. **Realm Isolation**: Each tenant gets its own realm (managed Keycloak)
|
|
1157
|
+
|
|
1158
|
+
---
|
|
1159
|
+
|
|
1160
|
+
## Important Notes and Best Practices
|
|
1161
|
+
|
|
1162
|
+
### 1. Tenant ID Resolution
|
|
1163
|
+
|
|
1164
|
+
**Critical Distinction**:
|
|
1165
|
+
|
|
1166
|
+
- `tenantId`: UUID string (used in API calls)
|
|
1167
|
+
- `tenant.id`: MongoDB ObjectId (stored in AuthProvider.tenant)
|
|
1168
|
+
|
|
1169
|
+
**Usage**:
|
|
1170
|
+
|
|
1171
|
+
```typescript
|
|
1172
|
+
// Frontend passes tenantId (UUID)
|
|
1173
|
+
// Backend resolves to MongoDB id for storage
|
|
1174
|
+
const tenant = await tenantRepository.find({ tenantId });
|
|
1175
|
+
authProvider.tenant = tenant.id; // MongoDB ObjectId
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
### 2. One Provider Per Tenant
|
|
1179
|
+
|
|
1180
|
+
**Important**: Each tenant can have only one auth provider. The system:
|
|
1181
|
+
|
|
1182
|
+
- Checks for existing provider when creating
|
|
1183
|
+
- Shows warning if provider already exists
|
|
1184
|
+
- Allows editing existing provider instead
|
|
1185
|
+
|
|
1186
|
+
### 3. Self-Hosted vs Managed Keycloak
|
|
1187
|
+
|
|
1188
|
+
**Managed Keycloak**:
|
|
1189
|
+
|
|
1190
|
+
- Realm is created automatically
|
|
1191
|
+
- Realm is deleted when provider is deleted
|
|
1192
|
+
- Uses internal admin service
|
|
1193
|
+
|
|
1194
|
+
**Self-Hosted Keycloak**:
|
|
1195
|
+
|
|
1196
|
+
- Realm must exist before configuration
|
|
1197
|
+
- Realm is not deleted when provider is deleted
|
|
1198
|
+
- Requires admin credentials
|
|
1199
|
+
- Uses tenant admin service
|
|
1200
|
+
|
|
1201
|
+
### 4. Secret Management
|
|
1202
|
+
|
|
1203
|
+
**Storage**:
|
|
1204
|
+
|
|
1205
|
+
- Secrets stored in environment service, not database
|
|
1206
|
+
- Retrieved on-demand when needed
|
|
1207
|
+
- Never logged or exposed in responses
|
|
1208
|
+
|
|
1209
|
+
**Keycloak Client Secret**:
|
|
1210
|
+
|
|
1211
|
+
- Fetched from Keycloak API (not stored)
|
|
1212
|
+
- Regenerated deterministically if needed
|
|
1213
|
+
- Different for managed vs self-hosted
|
|
1214
|
+
|
|
1215
|
+
### 5. Identity Provider Configuration
|
|
1216
|
+
|
|
1217
|
+
**Supported Providers**:
|
|
1218
|
+
|
|
1219
|
+
- Google, GitHub, Facebook, Microsoft, etc.
|
|
1220
|
+
- Each requires client ID and secret from provider
|
|
1221
|
+
- Can be enabled/disabled per provider
|
|
1222
|
+
|
|
1223
|
+
**Configuration**:
|
|
1224
|
+
|
|
1225
|
+
- Configured asynchronously via Inngest
|
|
1226
|
+
- Individual provider failures don't stop others
|
|
1227
|
+
- Updates require full provider array
|
|
1228
|
+
|
|
1229
|
+
### 6. Auth Flow Changes
|
|
1230
|
+
|
|
1231
|
+
**Important**: Changing auth flow (PKCE ↔ Implicit) requires:
|
|
1232
|
+
|
|
1233
|
+
- Deleting old client
|
|
1234
|
+
- Creating new client with new flow
|
|
1235
|
+
- This is handled automatically by Inngest
|
|
1236
|
+
|
|
1237
|
+
### 7. Credential Testing
|
|
1238
|
+
|
|
1239
|
+
**Purpose**: Verify configuration before saving or after changes.
|
|
1240
|
+
|
|
1241
|
+
**Process**:
|
|
1242
|
+
|
|
1243
|
+
- Uses OAuth2 client credentials flow
|
|
1244
|
+
- Attempts to obtain access token
|
|
1245
|
+
- Returns success/failure with details
|
|
1246
|
+
|
|
1247
|
+
**Best Practice**: Always test credentials after configuration changes.
|
|
1248
|
+
|
|
1249
|
+
### 8. Redirect URI Validation
|
|
1250
|
+
|
|
1251
|
+
**Format**: Must be valid URLs
|
|
1252
|
+
|
|
1253
|
+
- `https://example.com/callback`
|
|
1254
|
+
- `http://localhost:3000/callback` (development)
|
|
1255
|
+
|
|
1256
|
+
**Web Origins**: Automatically extracted from redirect URIs
|
|
1257
|
+
|
|
1258
|
+
- Used for CORS configuration
|
|
1259
|
+
- Must match redirect URI origins
|
|
1260
|
+
|
|
1261
|
+
### 9. Error Recovery
|
|
1262
|
+
|
|
1263
|
+
**Keycloak API Failures**:
|
|
1264
|
+
|
|
1265
|
+
- Logged but may not fail entire operation
|
|
1266
|
+
- Identity provider failures are non-blocking
|
|
1267
|
+
- Realm/client creation failures are blocking
|
|
1268
|
+
|
|
1269
|
+
**Retry Strategy**:
|
|
1270
|
+
|
|
1271
|
+
- Inngest functions can be retried
|
|
1272
|
+
- Service operations are idempotent where possible
|
|
1273
|
+
|
|
1274
|
+
### 10. Type Safety
|
|
1275
|
+
|
|
1276
|
+
**Key Interfaces**:
|
|
1277
|
+
|
|
1278
|
+
- `IAuthProvider`: Auth provider data structure
|
|
1279
|
+
- `IAuthProviderInput`: Input for create/update
|
|
1280
|
+
- `IKeycloakConfig`: Keycloak configuration
|
|
1281
|
+
- `IAuth0Config`: Auth0 configuration
|
|
1282
|
+
|
|
1283
|
+
**Type Guards**:
|
|
1284
|
+
|
|
1285
|
+
- Always check provider type before accessing config
|
|
1286
|
+
- Handle undefined/null cases gracefully
|
|
1287
|
+
|
|
1288
|
+
---
|
|
1289
|
+
|
|
1290
|
+
## Summary
|
|
1291
|
+
|
|
1292
|
+
The Auth Provider Management System provides a comprehensive interface for managing authentication providers (Keycloak and Auth0) for tenants. It leverages React, XState for form state management, GraphQL for data operations, and Inngest for asynchronous Keycloak configuration.
|
|
1293
|
+
|
|
1294
|
+
**Key Takeaways**:
|
|
1295
|
+
|
|
1296
|
+
**Frontend**:
|
|
1297
|
+
|
|
1298
|
+
- ✅ Multi-step form with XState machine
|
|
1299
|
+
- ✅ Support for Keycloak (managed/self-hosted) and Auth0
|
|
1300
|
+
- ✅ Credential testing before saving
|
|
1301
|
+
- ✅ Configuration details viewing
|
|
1302
|
+
- ✅ One provider per tenant constraint
|
|
1303
|
+
|
|
1304
|
+
**Backend**:
|
|
1305
|
+
|
|
1306
|
+
- ✅ Event-driven architecture with Inngest
|
|
1307
|
+
- ✅ Keycloak realm and client management
|
|
1308
|
+
- ✅ Identity provider configuration
|
|
1309
|
+
- ✅ Secure secret management via environment service
|
|
1310
|
+
- ✅ Support for both managed and self-hosted Keycloak
|
|
1311
|
+
- ✅ Auth flow change handling (PKCE ↔ Implicit)
|
|
1312
|
+
|
|
1313
|
+
## Testing
|
|
1314
|
+
|
|
1315
|
+
For testing keycloak authentication using PKCE and Implicit flow follow this example
|
|
1316
|
+
|
|
1317
|
+
https://github.com/huzaifaali14/keycloak-auth
|