diff --git a/web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts b/web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts
index 14700b1506..09422aabe4 100644
--- a/web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts
+++ b/web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts
@@ -1,37 +1,9 @@
-import "@goauthentik/admin/applications/wizard/ak-wizard-title";
-import "@goauthentik/admin/common/ak-crypto-certificate-search";
-import "@goauthentik/admin/common/ak-flow-search/ak-branded-flow-search";
-import {
- makeOAuth2PropertyMappingsSelector,
- oauth2PropertyMappingsProvider,
-} from "@goauthentik/admin/providers/oauth2/OAuth2PropertyMappings.js";
-import {
- clientTypeOptions,
- issuerModeOptions,
- redirectUriHelp,
- subjectModeOptions,
-} from "@goauthentik/admin/providers/oauth2/OAuth2ProviderForm";
-import {
- makeSourceSelector,
- oauth2SourcesProvider,
-} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js";
+import { renderForm } from "@goauthentik/admin/providers/oauth2/OAuth2ProviderFormForm.js";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
-import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
-import "@goauthentik/components/ak-number-input";
-import "@goauthentik/components/ak-radio-input";
-import "@goauthentik/components/ak-switch-input";
-import "@goauthentik/components/ak-text-input";
-import "@goauthentik/components/ak-textarea-input";
-import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
-import "@goauthentik/elements/forms/FormGroup";
-import "@goauthentik/elements/forms/HorizontalFormElement";
-import { msg } from "@lit/localize";
import { customElement, state } from "@lit/reactive-element/decorators.js";
-import { html, nothing } from "lit";
-import { ifDefined } from "lit/directives/if-defined.js";
-import { ClientTypeEnum, FlowsInstancesListDesignationEnum, SourcesApi } from "@goauthentik/api";
+import { SourcesApi } from "@goauthentik/api";
import { type OAuth2Provider, type PaginatedOAuthSourceList } from "@goauthentik/api";
import BaseProviderPanel from "../BaseProviderPanel";
@@ -59,227 +31,10 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel {
render() {
const provider = this.wizard.provider as OAuth2Provider | undefined;
const errors = this.wizard.errors.provider;
-
- return html`${msg("Configure OAuth2/OpenId Provider")}
-
`;
+ const showClientSecretCallback = (show: boolean) => {
+ this.showClientSecret = show;
+ };
+ return renderForm(provider ?? {}, errors, this.showClientSecret, showClientSecretCallback);
}
}
diff --git a/web/src/admin/providers/ProviderWizard.ts b/web/src/admin/providers/ProviderWizard.ts
index 51e159c671..2c7ba266b9 100644
--- a/web/src/admin/providers/ProviderWizard.ts
+++ b/web/src/admin/providers/ProviderWizard.ts
@@ -58,6 +58,7 @@ export class ProviderWizard extends AKElement {
}}
>
html`${m}
`,
-)}`;
+import { renderForm } from "./OAuth2ProviderFormForm.js";
/**
* Form page for OAuth2 Authentication Method
@@ -145,233 +40,11 @@ export class OAuth2ProviderFormPage extends BaseProviderForm {
}
}
- renderForm(): TemplateResult {
- const provider = this.instance;
-
- return html`
-
-
- ${msg("Protocol settings")}
-
-
-
-
- ${msg("Flow settings")}
-
-
-
-
- ${msg("Advanced protocol settings")}
-
-
-
-
- ${msg("Machine-to-Machine authentication settings")}
-
- `;
+ renderForm() {
+ const showClientSecretCallback = (show: boolean) => {
+ this.showClientSecret = show;
+ };
+ return renderForm(this.instance ?? {}, [], this.showClientSecret, showClientSecretCallback);
}
}
diff --git a/web/src/admin/providers/oauth2/OAuth2ProviderFormForm.ts b/web/src/admin/providers/oauth2/OAuth2ProviderFormForm.ts
new file mode 100644
index 0000000000..35a2ac4cea
--- /dev/null
+++ b/web/src/admin/providers/oauth2/OAuth2ProviderFormForm.ts
@@ -0,0 +1,354 @@
+import "@goauthentik/admin/common/ak-crypto-certificate-search";
+import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
+import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
+import "@goauthentik/components/ak-radio-input";
+import "@goauthentik/components/ak-text-input";
+import "@goauthentik/components/ak-textarea-input";
+import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
+import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
+import "@goauthentik/elements/forms/FormGroup";
+import "@goauthentik/elements/forms/HorizontalFormElement";
+import "@goauthentik/elements/forms/Radio";
+import "@goauthentik/elements/forms/SearchSelect";
+import "@goauthentik/elements/utils/TimeDeltaHelp";
+
+import { msg } from "@lit/localize";
+import { html } from "lit";
+import { ifDefined } from "lit/directives/if-defined.js";
+
+import {
+ ClientTypeEnum,
+ FlowsInstancesListDesignationEnum,
+ IssuerModeEnum,
+ OAuth2Provider,
+ SubModeEnum,
+ ValidationError,
+} from "@goauthentik/api";
+
+import {
+ makeOAuth2PropertyMappingsSelector,
+ oauth2PropertyMappingsProvider,
+} from "./OAuth2PropertyMappings.js";
+import { makeSourceSelector, oauth2SourcesProvider } from "./OAuth2Sources.js";
+
+export const clientTypeOptions = [
+ {
+ label: msg("Confidential"),
+ value: ClientTypeEnum.Confidential,
+ default: true,
+ description: html`${msg(
+ "Confidential clients are capable of maintaining the confidentiality of their credentials such as client secrets",
+ )}`,
+ },
+ {
+ label: msg("Public"),
+ value: ClientTypeEnum.Public,
+ description: html`${msg(
+ "Public clients are incapable of maintaining the confidentiality and should use methods like PKCE. ",
+ )}`,
+ },
+];
+
+export const subjectModeOptions = [
+ {
+ label: msg("Based on the User's hashed ID"),
+ value: SubModeEnum.HashedUserId,
+ default: true,
+ },
+ {
+ label: msg("Based on the User's ID"),
+ value: SubModeEnum.UserId,
+ },
+ {
+ label: msg("Based on the User's UUID"),
+ value: SubModeEnum.UserUuid,
+ },
+ {
+ label: msg("Based on the User's username"),
+ value: SubModeEnum.UserUsername,
+ },
+ {
+ label: msg("Based on the User's Email"),
+ value: SubModeEnum.UserEmail,
+ description: html`${msg("This is recommended over the UPN mode.")}`,
+ },
+ {
+ label: msg("Based on the User's UPN"),
+ value: SubModeEnum.UserUpn,
+ description: html`${msg(
+ "Requires the user to have a 'upn' attribute set, and falls back to hashed user ID. Use this mode only if you have different UPN and Mail domains.",
+ )}`,
+ },
+];
+
+export const issuerModeOptions = [
+ {
+ label: msg("Each provider has a different issuer, based on the application slug"),
+ value: IssuerModeEnum.PerProvider,
+ default: true,
+ },
+ {
+ label: msg("Same identifier is used for all providers"),
+ value: IssuerModeEnum.Global,
+ },
+];
+
+const redirectUriHelpMessages = [
+ msg(
+ "Valid redirect URLs after a successful authorization flow. Also specify any origins here for Implicit flows.",
+ ),
+ msg(
+ "If no explicit redirect URIs are specified, the first successfully used redirect URI will be saved.",
+ ),
+ msg(
+ 'To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have.',
+ ),
+];
+
+export const redirectUriHelp = html`${redirectUriHelpMessages.map(
+ (m) => html`${m}
`,
+)}`;
+
+type ShowClientSecret = (show: boolean) => void;
+const defaultShowClientSecret: ShowClientSecret = (_show) => undefined;
+
+export function renderForm(
+ provider: Partial,
+ errors: ValidationError,
+ showClientSecret = false,
+ showClientSecretCallback: ShowClientSecret = defaultShowClientSecret,
+) {
+ return html`
+
+
+ ${msg("Protocol settings")}
+
+
+
+
+ ${msg("Flow settings")}
+
+
+
+
+ ${msg("Advanced protocol settings")}
+
+
+
+
+ ${msg("Machine-to-Machine authentication settings")}
+
+ `;
+}
diff --git a/web/src/elements/forms/FormGroup.ts b/web/src/elements/forms/FormGroup.ts
index 285bc5acf0..92986eaecf 100644
--- a/web/src/elements/forms/FormGroup.ts
+++ b/web/src/elements/forms/FormGroup.ts
@@ -44,37 +44,43 @@ export class FormGroup extends AKElement {
}
render(): TemplateResult {
- return html`