+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "xak-flow-frame": FlowFrameStage;
+ }
+}
diff --git a/web/src/user/user-settings/mfa/MFADeviceForm.ts b/web/src/user/user-settings/mfa/MFADeviceForm.ts
index c470d32bb3fb..7ac6f9e4d7ab 100644
--- a/web/src/user/user-settings/mfa/MFADeviceForm.ts
+++ b/web/src/user/user-settings/mfa/MFADeviceForm.ts
@@ -1,8 +1,9 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
+import { SentryIgnoredError } from "@goauthentik/common/errors";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
-import { msg } from "@lit/localize";
+import { msg, str } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
@@ -10,11 +11,11 @@ import { ifDefined } from "lit/directives/if-defined.js";
import { AuthenticatorsApi, Device } from "@goauthentik/api";
@customElement("ak-user-mfa-form")
-export class MFADeviceForm extends ModelForm {
+export class MFADeviceForm extends ModelForm {
@property()
deviceType!: string;
- async loadInstance(pk: number): Promise {
+ async loadInstance(pk: string): Promise {
const devices = await new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsAllList();
return devices.filter((device) => {
return device.pk === pk && device.type === this.deviceType;
@@ -29,36 +30,38 @@ export class MFADeviceForm extends ModelForm {
switch (this.instance?.type) {
case "authentik_stages_authenticator_duo.DuoDevice":
await new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsDuoUpdate({
- id: this.instance?.pk,
+ id: parseInt(this.instance?.pk, 10),
duoDeviceRequest: device,
});
break;
case "authentik_stages_authenticator_sms.SMSDevice":
await new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsSmsUpdate({
- id: this.instance?.pk,
+ id: parseInt(this.instance?.pk, 10),
sMSDeviceRequest: device,
});
break;
case "authentik_stages_authenticator_totp.TOTPDevice":
await new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsTotpUpdate({
- id: this.instance?.pk,
+ id: parseInt(this.instance?.pk, 10),
tOTPDeviceRequest: device,
});
break;
case "authentik_stages_authenticator_static.StaticDevice":
await new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsStaticUpdate({
- id: this.instance?.pk,
+ id: parseInt(this.instance?.pk, 10),
staticDeviceRequest: device,
});
break;
case "authentik_stages_authenticator_webauthn.WebAuthnDevice":
await new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsWebauthnUpdate({
- id: this.instance?.pk,
+ id: parseInt(this.instance?.pk, 10),
webAuthnDeviceRequest: device,
});
break;
default:
- break;
+ throw new SentryIgnoredError(
+ msg(str`Device type ${device.verboseName} cannot be edited`),
+ );
}
return device;
}
diff --git a/web/src/user/user-settings/mfa/MFADevicesPage.ts b/web/src/user/user-settings/mfa/MFADevicesPage.ts
index 85e72094e182..29a82c48e373 100644
--- a/web/src/user/user-settings/mfa/MFADevicesPage.ts
+++ b/web/src/user/user-settings/mfa/MFADevicesPage.ts
@@ -1,4 +1,5 @@
import { AndNext, DEFAULT_CONFIG } from "@goauthentik/common/api/config";
+import { SentryIgnoredError } from "@goauthentik/common/errors";
import { deviceTypeName } from "@goauthentik/common/labels";
import { getRelativeTime } from "@goauthentik/common/utils";
import "@goauthentik/elements/buttons/Dropdown";
@@ -10,7 +11,7 @@ import { PaginatedResponse, Table, TableColumn } from "@goauthentik/elements/tab
import "@goauthentik/user/user-settings/mfa/MFADeviceForm";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
-import { msg } from "@lit/localize";
+import { msg, str } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
@@ -89,7 +90,7 @@ export class MFADevicesPage extends Table {
async deleteWrapper(device: Device) {
const api = new AuthenticatorsApi(DEFAULT_CONFIG);
- const id = { id: device.pk };
+ const id = { id: parseInt(device.pk, 10) };
switch (device.type) {
case "authentik_stages_authenticator_duo.DuoDevice":
return api.authenticatorsDuoDestroy(id);
@@ -102,7 +103,9 @@ export class MFADevicesPage extends Table {
case "authentik_stages_authenticator_webauthn.WebAuthnDevice":
return api.authenticatorsWebauthnDestroy(id);
default:
- break;
+ throw new SentryIgnoredError(
+ msg(str`Device type ${device.verboseName} cannot be deleted`),
+ );
}
}
diff --git a/website/docs/add-secure-apps/flows-stages/stages/authenticator_endpoint_gdtc/index.md b/website/docs/add-secure-apps/flows-stages/stages/authenticator_endpoint_gdtc/index.md
new file mode 100644
index 000000000000..096941790481
--- /dev/null
+++ b/website/docs/add-secure-apps/flows-stages/stages/authenticator_endpoint_gdtc/index.md
@@ -0,0 +1,78 @@
+---
+title: Endpoint Authenticator Google Device Trust Connector Stage
+---
+
+Enterprise
+authentik 2024.10+
+
+---
+
+With this stage, authentik can validate users' Chrome browsers and ensure that users' devices are compliant and up-to-date.
+
+:::info
+This stage only works with Google Chrome, as it relies on the [Chrome Verified Access API](https://developers.google.com/chrome/verified-access).
+:::
+
+## Configuration
+
+The main steps to set up your Google workspace are as follows:
+
+1. [Create your Google Cloud Project](#create-a-google-cloud-project)
+2. [Create a service account](#create-a-service-account)
+3. [Set credentials for the service account](#set-credentials-for-the-service-account)
+4. [Define access and scope in the Admin Console](#set-credentials-for-the-service-account)
+
+For detailed instructions, refer to Google documentation.
+
+### Create a Google cloud project
+
+1. Open the Google Cloud Console (https://cloud.google.com/cloud-console).
+2. In upper left, click the drop-down box to open the **Select a project** modal box, and then select **New Project**.
+3. Create a new project and give it a name like "authentik GWS".
+4. Use the search bar at the top of your new project page to search for "API Library".
+5. On the **API Library** page, use the search bar again to find "Chrome Verified Access API".
+6. On the **Chrome Verified Access API** page, click **Enable**.
+
+### Create a service account
+
+1. After the new Chrome Verified Access API is enabled (it might take a few minutes), return to the Google Cloud console home page (click on **Google Cloud** in upper left).
+2. Use the search bar to find and navigate to the **IAM** page.
+3. On the **IAM** page, click **Service Accounts** in the left navigation pane.
+4. At the top of the **Service Accounts** page, click **Create Service Account**.
+
+- Under **Service account details** page, define the **Name** and **Description** for the new service account, and then click **Create and Continue**.
+- Under **Grant this service account access to project** you do not need to define a role, so click **Continue**.
+- Under **Grant users access to project** you do not need to define a role, so click **Done** to complete the creation of the service account.
+
+### Set credentials for the service account
+
+1. On the **Service accounts** page, click the account that you just created.
+2. Click the **Keys** tab at top of the page, the click **Add Key -> Create new key**.
+3. In the Create modal box, select JSON as the key type, and then click **Create**.
+ A pop-up displays with the private key, and the key is saved to your computer as a JSON file.
+ Later, when you create the stage in authentik, you will add this key in the **Credentials** field.
+4. On the service account page, click the **Details** tab, and expand the **Advanced settings** area.
+5. Log in to the Admin Console, and then navigate to **Chrome browser -> Connectors**.
+6. Click on **New Provider Configuration**.
+7. Under Okta, click "Set up".
+8. Enter a name.
+9. Enter the URL: https://authentik.company/endpoint/gdtc/chrome/
+10. Under Service accounts, enter the full name of the service account created above, for example `authentik-gdtc-docs@authentik-enterprise-dev.iam.gserviceaccount.com`.
+
+### Create the stage
+
+1. Log in as an admin to authentik, and go to the Admin interface.
+
+2. In the Admin interface, navigate to **Flows -> Stages**.
+
+3. Click **Create**, and select **Endpoint Authenticator Google Device Trust Connector Stage**, and in the **New stage** modal box, define the following fields:
+
+ - **Name**: define a descriptive name, such as "chrome-device-trust".
+
+ - **Google Verified Access API**
+
+ - **Credentials**: paste the contents of the JSON file (the key) that you downloaded earlier.
+
+4. Click **Finish**.
+
+After creating the stage, it can be used in any flow. Compared to other Authenticator stages, this stage does not require enrollment. Instead of adding an [Authenticator Validation Stage](../authenticator_validate/index.md), this stage only verifies the users' browser.
diff --git a/website/sidebars.js b/website/sidebars.js
index acca54bf1dc2..f45c88cdb879 100644
--- a/website/sidebars.js
+++ b/website/sidebars.js
@@ -282,6 +282,7 @@ export default {
},
items: [
"add-secure-apps/flows-stages/stages/authenticator_duo/index",
+ "add-secure-apps/flows-stages/stages/authenticator_endpoint_gdtc/index",
"add-secure-apps/flows-stages/stages/authenticator_sms/index",
"add-secure-apps/flows-stages/stages/authenticator_static/index",
"add-secure-apps/flows-stages/stages/authenticator_totp/index",