diff --git a/changes/48077-observer-managed-account-action.md b/changes/48077-observer-managed-account-action.md
new file mode 100644
index 0000000000..ef4ac861b9
--- /dev/null
+++ b/changes/48077-observer-managed-account-action.md
@@ -0,0 +1 @@
+- Fixed observers not seeing the "Show managed account" action on a macOS host's details page, even though the API already allows them to view the managed local account password.
diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx
index 5011bd9af1..8aaf42da98 100644
--- a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx
+++ b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/HostActionsDropdown.tests.tsx
@@ -2108,6 +2108,68 @@ describe("Host Actions Dropdown", () => {
expect(screen.getByText("Show managed account")).toBeInTheDocument();
});
+ it("renders the action for a global observer (the API authorizes any host-reader)", async () => {
+ const render = createCustomRenderer({
+ context: {
+ app: {
+ isGlobalObserver: true,
+ isPremiumTier: true,
+ currentUser: createMockUser(),
+ },
+ },
+ });
+
+ const { user } = render(
+
+ );
+
+ await user.click(screen.getByText("Actions"));
+
+ expect(screen.getByText("Show managed account")).toBeInTheDocument();
+ });
+
+ it("renders the action for a team observer", async () => {
+ const render = createCustomRenderer({
+ context: {
+ app: {
+ isTeamObserver: true,
+ isPremiumTier: true,
+ currentUser: createMockUser(),
+ },
+ },
+ });
+
+ const { user } = render(
+
+ );
+
+ await user.click(screen.getByText("Actions"));
+
+ expect(screen.getByText("Show managed account")).toBeInTheDocument();
+ });
+
it("hides the action when managed local account is not enabled", async () => {
const render = createCustomRenderer({
context: {
diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.tsx
index ff8104fee2..c312706ab2 100644
--- a/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.tsx
+++ b/frontend/pages/hosts/details/HostDetailsPage/HostActionsDropdown/helpers.tsx
@@ -388,10 +388,6 @@ const canShowManagedAccount = (config: IHostActionConfigOptions) => {
const {
isPremiumTier,
isConnectedToFleetMdm,
- isGlobalAdmin,
- isGlobalMaintainer,
- isTeamAdmin,
- isTeamMaintainer,
hostPlatform,
hostMdmEnrollmentStatus,
isManagedLocalAccountEnabled,
@@ -403,7 +399,12 @@ const canShowManagedAccount = (config: IHostActionConfigOptions) => {
if (!isManagedLocalAccountEnabled && !config.managedAccountStatus) {
return false;
}
- return isGlobalAdmin || isGlobalMaintainer || isTeamAdmin || isTeamMaintainer;
+ // Not role-gated: the backend authorizes this action for any user who can
+ // read the host (including observers), matching the other "show secret"
+ // actions above (disk encryption key, Recovery Lock password). Restricting
+ // it to admins/maintainers here hid the action from observers even though
+ // the API returns the managed account password to them.
+ return true;
};
const canClearPasscode = (config: IHostActionConfigOptions) => {