Skip to content

feat(admin): plugin capabilities for WorkOS user management - #77

Open
bordoni wants to merge 7 commits into
mainfrom
feat/workos-capabilities
Open

bordoni wants to merge 7 commits into
mainfrom
feat/workos-capabilities

Conversation

@bordoni

@bordoni bordoni commented Oct 17, 2026

Copy link
Copy Markdown
Owner

The plugin's user-management actions check manage_options, edit_users or edit_user directly. A site that wants a support role that can look up WorkOS users or send a password reset, without full user-editing rights, has no way to grant just that.

Changes

  • New WorkOS\Capabilities adds four capabilities through map_meta_cap. Each resolves to the core capability its check used before, with the same arguments:
Capability Maps to
workos_view_users manage_options
workos_send_password_reset edit_user (per user, so self-service keeps working)
workos_change_email edit_user (per user)
workos_manage_lockouts edit_users
  • Default roles always take that path, so nobody gains or loses access. When a user holds one of the capabilities directly (on a role or on the account), that grant decides: true allows the action for any user, false takes it away. On multisite a direct grant still can't target a super admin.
  • Switched to the new capabilities: the password-reset endpoint, row action, user-edit panel and shortcode; change-email initiate, the capability path of cancel, row action, panel and shortcode; the WorkOS → Users submenu and GET /admin/users.
  • Left alone: Settings and the other WorkOS admin pages stay on manage_options. The user-edit WorkOS panel and sync/re-sync stay on edit_users. An email change for another account still commits immediately only with edit_users, so a role with just workos_change_email gets the verified flow.
  • WorkOS Users rows carry can_send_password_reset and can_change_email, and the screen shows only the buttons the caller can use.
  • workos_manage_lockouts is defined for the lockouts endpoint (Look up and clear sign-in lockouts from the admin and WP-CLI #61) to adopt. Nothing checks it yet.
  • New docs/capabilities.md with the table and a custom-role example. The password-reset and change-email docs, README and AGENTS.md point to it.

Verified

  • New CapabilitiesTest: for administrator, editor, author and subscriber, acting on themselves, another subscriber and another admin, every plugin capability gives the same answer as the core check it replaced, and matches an explicit expected table. Logged out gets nothing. It also covers a role with only workos_send_password_reset, each capability granted alone, false denying, a grant on one user, and the row actions, panels, shortcodes and submenu following their capability.
  • REST: a role with only workos_send_password_reset sends a reset for another user and gets 403 from the settings routes. A role with workos_change_email gets the verified flow for another user and can cancel it. A role with workos_view_users lists users. Editors still get 403 on all three.
  • Checked against WordPress's menu code that a role with only workos_view_users keeps the WorkOS menu with just Users in it, can open Users, and can't open Settings.
  • wpunit: 789 tests plus the 15 in the constants group pass (main: 761 plus 15). phpcs, phpstan, bun run build and tsc --noEmit pass.

Closes #65

…d logout URL

Adds workos_get_valid_access_token(), workos_send_password_reset() and workos_get_logout_url(), so sites no longer call the WorkOS API themselves to refresh tokens, send resets or build the logout URL.

- workos_get_valid_access_token() (User::get_valid_access_token()) returns the stored token while it has more than 60 seconds left, otherwise refreshes it through Api\Client::refresh_session() and stores the new pair with Login::store_tokens(). workos_get_access_token() keeps returning the token as stored.
- workos_send_password_reset() calls the new PasswordResetAdmin\RestApi::send_for_user(), the code behind the admin reset route, so the rate limits, RedirectValidator check and activity log row are shared. The route now calls it after its capability check.
- workos_get_logout_url() (User::get_logout_url()) returns the WorkOS sessions/logout URL for the stored session, or wp_logout_url() when there is none.
- workos_get_user_id() already existed; it is documented with the rest in docs/php-helpers.md.

Closes #63
Add workos_view_users, workos_send_password_reset, workos_change_email
and workos_manage_lockouts, resolved through map_meta_cap. Each maps to
the core capability its check used before (manage_options, edit_user,
edit_user, edit_users), so default roles keep exactly the access they
had, including self-service password reset and email change. A role
granted a capability directly gets that action; false denies it.

Switch the password-reset and change-email checks and the WorkOS Users
screen to the new capabilities. Settings stay on manage_options, and the
immediate admin email change still needs edit_users.
…lity

GET /workos/v1/admin/users now checks workos_view_users (still
manage_options by default). Each row carries can_send_password_reset and
can_change_email for the caller, and the React screen shows only the
buttons the caller can use.
Add docs/capabilities.md with the mapping table, what stays on core
capabilities, and how to grant them to a custom role. Point the
password-reset and change-email docs, README and AGENTS.md at the new
capabilities.

Closes #65
@bordoni bordoni added this to the 1.0.11 milestone Oct 17, 2026
@bordoni bordoni added enhancement New feature or request area: admin WP-admin settings & screens labels Oct 17, 2026
@bordoni
bordoni added this pull request to stack #84 October 17, 2026 23:03
@bordoni bordoni modified the milestones: 1.0.11, 1.0.12 Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: admin WP-admin settings & screens enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plugin capabilities for WorkOS user management

1 participant