Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2eeafb4
feat(authkit): phase 1 foundation for custom WordPress-hosted AuthKit
bordoni Apr 22, 2026
54041bd
feat(authkit): phase 2 public REST /auth/* endpoints + profile routing
bordoni Apr 22, 2026
124182c
feat(authkit): phases 3-5 React shell + wp-login takeover + routes
bordoni Apr 22, 2026
41b88cc
feat(authkit): Radar SDK client + React admin profile editor
bordoni Apr 22, 2026
82bbb63
fix(authkit): address four findings from the phase-6 security review
bordoni Apr 22, 2026
c9f1d87
refactor(authkit): move rewrite registration into FrontendRoute
bordoni Apr 22, 2026
1b78ed2
refactor(authkit): replace \FQN class refs with use statements
bordoni Apr 22, 2026
8fb7d7e
refactor(authkit): convert JS → TypeScript + TSX
bordoni Apr 22, 2026
f542864
docs(authkit): document Custom AuthKit + TypeScript migration
bordoni Apr 22, 2026
a25f71d
docs(authkit): revert to bun for JS package management
bordoni Apr 22, 2026
027b3f6
feat(public-api): add WorkOS\User helper + global shortcuts
bordoni Apr 22, 2026
e532358
style(phpcs): clear all WPCS violations flagged by CI
bordoni Apr 23, 2026
f415fc6
feat(authkit): integrate Login Mode setting with Login Profiles
bordoni Apr 23, 2026
0a4f4e9
fix(authkit): eliminate rate-limiter race under concurrent load (revi…
bordoni Apr 23, 2026
066669f
fix(authkit): cap Radar action-token length at 2 KiB (review #2)
bordoni Apr 23, 2026
28ed544
fix(authkit): rate-limit MFA challenge per factor id (review #3)
bordoni Apr 23, 2026
7829e1a
fix(authkit): use profile-scoped nonce in OAuth state (review #4)
bordoni Apr 23, 2026
e3f52fa
fix(authkit): flatten password-reset response time (review #5)
bordoni Apr 23, 2026
73e8615
fix(authkit): re-validate primary_color before CSS emission (review #6)
bordoni Apr 23, 2026
cc8224f
fix(authkit): clean error response from signup/verify (review #7)
bordoni Apr 23, 2026
ef7223e
docs(authkit): clarify unsigned JWT exp extraction (review #8)
bordoni Apr 23, 2026
a53ed31
fix(authkit): validate organization_id format on Profile save (review…
bordoni Apr 23, 2026
0a07ec7
docs(authkit): document router default fallback behavior (review #10)
bordoni Apr 23, 2026
e422367
refactor(authkit): drop unused remember flag from LoginCompleter (rev…
bordoni Apr 23, 2026
2997525
fix(authkit): validate logo attachment mime on profile save (review #12)
bordoni Apr 23, 2026
8caf6b8
feat(authkit): i18n browser bundles + live org picker for Login Profiles
bordoni Apr 23, 2026
0836e3a
fix: address mauteri review feedback + PHPCS on feature/custom-authkit
bordoni Apr 23, 2026
5858dbe
refactor(api): add Client::safe_remote_request wrapper
bordoni Apr 23, 2026
7fb470a
feat(authkit): SlotFill + hook-based extensibility for login UI
bordoni Apr 24, 2026
044bd2a
fix(authkit): unwrap wp.media Backbone Model before reading attachment
bordoni Apr 24, 2026
5e89b8e
feat(authkit): SSR profile list + deep-link URLs in the editor
bordoni Apr 24, 2026
74f1cf9
fix(authkit): avoid print_emoji_styles deprecation from core
bordoni Apr 24, 2026
4b21561
fix(authkit): drop organization_id from social-OAuth authorize URL
bordoni Apr 24, 2026
152c1ee
fix(authkit): collapse empty SlotFill placeholders so card spacing st…
bordoni Apr 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 98 additions & 34 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Per-environment constants (take priority over generic):
| `src/WorkOS/Plugin.php` | Bootstrap, constants, container init, app boot |
| `src/WorkOS/App.php` | Static facade for the DI container |
| `src/WorkOS/Config.php` | Centralized config with constant overrides |
| `src/WorkOS/User.php` | Public read-only helper for WorkOS metadata on WP users (`is_sso`, `has_active_session`, `get_workos_id`, `get_access_token`, `snapshot`) |
| `src/WorkOS/Controller.php` | Main controller, registers all feature controllers |
| `src/WorkOS/Contracts/Container.php` | DI container (di52-based) |
| `src/WorkOS/Contracts/Controller.php` | Abstract base controller with `isActive()` |
Expand All @@ -79,6 +80,10 @@ Per-environment constants (take priority over generic):
| `src/WorkOS/Admin/DiagnosticsPage.php` | System diagnostics page |
| `src/WorkOS/Admin/OnboardingPage.php` | Onboarding wizard UI |
| `src/WorkOS/Admin/OnboardingAjax.php` | Onboarding wizard AJAX handlers |
| **Admin — Login Profiles (Custom AuthKit)** | |
| `src/WorkOS/Admin/LoginProfiles/Controller.php` | Wires Login Profile admin page + CRUD REST |
| `src/WorkOS/Admin/LoginProfiles/AdminPage.php` | Admin submenu that mounts the React editor |
| `src/WorkOS/Admin/LoginProfiles/RestApi.php` | `/wp-json/workos/v1/admin/profiles` CRUD (manage_options) |
| **Auth** | |
| `src/WorkOS/Auth/Controller.php` | Auth controller (login, registration, password reset, redirects) |
| `src/WorkOS/Auth/Login.php` | SSO login flow (redirect + headless modes) |
Expand All @@ -87,6 +92,19 @@ Per-environment constants (take priority over generic):
| `src/WorkOS/Auth/PasswordReset.php` | Password reset flow |
| `src/WorkOS/Auth/Redirect.php` | Role-based login redirects |
| `src/WorkOS/Auth/LogoutRedirect.php` | Role-based logout redirects |
| **Auth — Custom AuthKit (React shell)** | |
| `src/WorkOS/Auth/AuthKit/Controller.php` | Wires Login Profile CPT + takeover + shortcode + route |
| `src/WorkOS/Auth/AuthKit/Profile.php` | Immutable Login Profile value object |
| `src/WorkOS/Auth/AuthKit/ProfileRepository.php` | CPT-backed CRUD + default seeding |
| `src/WorkOS/Auth/AuthKit/ProfileRouter.php` | Rule-based profile resolution |
| `src/WorkOS/Auth/AuthKit/LoginCompleter.php` | Post-auth finalizer (EntitlementGate + MFA policy) |
| `src/WorkOS/Auth/AuthKit/LoginTakeover.php` | wp-login.php `action=login` takeover |
| `src/WorkOS/Auth/AuthKit/FrontendRoute.php` | `/workos/login/{profile}` rewrite + static `register_rewrite()` |
| `src/WorkOS/Auth/AuthKit/Shortcode.php` | `[workos_login_v2]` shortcode |
| `src/WorkOS/Auth/AuthKit/Renderer.php` | HTML shell + React bundle enqueue. Fires `workos_authkit_enqueue_assets` action and applies `workos_authkit_branding` / `workos_authkit_profile_data` / `workos_authkit_body_classes` filters — see `docs/extending-the-login-ui.md` |
| `src/WorkOS/Auth/AuthKit/Nonce.php` | Profile-scoped CSRF nonces |
| `src/WorkOS/Auth/AuthKit/RateLimiter.php` | Per-IP / per-email transient buckets |
| `src/WorkOS/Auth/AuthKit/Radar.php` | WorkOS Radar site-key + request-header extraction |
| **Organization** | |
| `src/WorkOS/Organization/Controller.php` | Organization controller |
| `src/WorkOS/Organization/Manager.php` | Organization CRUD and caching |
Expand Down Expand Up @@ -117,8 +135,18 @@ Per-environment constants (take priority over generic):
| `src/WorkOS/Sync/AuditLog.php` | Forward WP events to WorkOS Audit Logs |
| `src/WorkOS/Sync/AuditLogController.php` | Audit log controller |
| **REST** | |
| `src/WorkOS/REST/Controller.php` | REST controller |
| `src/WorkOS/REST/TokenAuth.php` | REST API Bearer token authentication |
| `src/WorkOS/REST/Controller.php` | REST controller (registers TokenAuth + Auth) |
| `src/WorkOS/REST/TokenAuth.php` | REST API Bearer token authentication (no lazy refresh) |
| **REST — Public Auth (Custom AuthKit)** | |
| `src/WorkOS/REST/Auth/Controller.php` | Wires all public `/wp-json/workos/v1/auth/*` endpoints |
| `src/WorkOS/REST/Auth/BaseEndpoint.php` | Shared profile + nonce + rate-limit + Radar helpers |
| `src/WorkOS/REST/Auth/Password.php` | `password/authenticate`, `password/reset/{start,confirm}` |
| `src/WorkOS/REST/Auth/MagicCode.php` | `magic/{send,verify}` |
| `src/WorkOS/REST/Auth/Session.php` | `nonce`, `session/{refresh,logout}` |
| `src/WorkOS/REST/Auth/Signup.php` | `signup/{create,verify}` |
| `src/WorkOS/REST/Auth/Invitation.php` | `invitation/{token}`, `invitation/accept` |
| `src/WorkOS/REST/Auth/OAuth.php` | `oauth/authorize-url` |
| `src/WorkOS/REST/Auth/Mfa.php` | `mfa/{challenge,verify,factors,totp/enroll,sms/enroll,factor/delete}` |
| **Webhook** | |
| `src/WorkOS/Webhook/Controller.php` | Webhook controller |
| `src/WorkOS/Webhook/Receiver.php` | Webhook event processing and signature verification |
Expand All @@ -131,10 +159,24 @@ Per-environment constants (take priority over generic):
| **Database** | |
| `src/WorkOS/Database/Schema.php` | DB schema creation and upgrades |
| **Helpers** | |
| `src/includes/functions-helpers.php` | Global `workos()` and `workos_log()` helpers |
| `src/includes/functions-helpers.php` | Global helpers: `workos()`, `workos_log()`, `workos_is_sso_user()`, `workos_has_active_session()`, `workos_get_user_id()`, `workos_get_access_token()` — the latter four proxy to `WorkOS\User` |
| **Browser — Custom AuthKit (TypeScript + TSX)** | |
| `src/js/authkit/index.tsx` | Entry + data-* hydration |
| `src/js/authkit/App.tsx` | Top-level step machine |
| `src/js/authkit/api.ts` | Fetch client w/ nonce + 401 refresh + Radar header |
| `src/js/authkit/flows.tsx` | 11 flow components (password, magic, signup, reset, mfa, invitation, complete) |
| `src/js/authkit/ui.tsx` | 11 primitives (Button, Input, Card, …) |
| `src/js/authkit/radar.ts` | WorkOS Radar SDK loader (+ `window.WorkOSRadar` augmentation) |
| `src/js/authkit/types.ts` | Shared interfaces (Profile, AuthResult, MfaRequired, Step, …) |
| `src/js/authkit/styles.css` | Scoped shell styles (CSS vars) |
| `src/js/admin-profiles/index.tsx` | Admin Login Profile editor (CRUD) |
| `src/js/admin-profiles/styles.css` | Scoped admin styles |
| **Build** | |
| `composer.json` | PHP dependencies |
| `package.json` | JS dependencies (bun) |
| `package.json` | JS dependencies (bun; uses `@wordpress/scripts` v30 + TypeScript strict) |
| `bun.lock` | Locked dependency graph (committed) |
| `tsconfig.json` | TypeScript config (strict, `jsx: react-jsx`, `noEmit: true`) |
| `webpack.config.js` | Extends `@wordpress/scripts` default config with authkit + admin-profiles entries |

## Build System

Expand All @@ -146,13 +188,18 @@ Per-environment constants (take priority over generic):
### Commands

```bash
bun install # Install dependencies
bun run build # Production build (wp-scripts)
bun run start # Development with watch
bun run lint:php # Lint PHP via PHPCS
bun run lint:php:fix # Auto-fix PHP lint issues
bun install # Install dependencies
bun run build # Production build (wp-scripts; transpiles .ts/.tsx via babel)
bun run start # Development with watch
bun run lint:ts # Type-check TypeScript (tsc --noEmit)
bun run lint:php # Lint PHP via PHPCS
bun run lint:php:fix # Auto-fix PHP lint issues
```

`@wordpress/scripts` v30 transpiles `.ts` / `.tsx` natively via its default
babel preset (no ts-loader, no custom webpack rules). `tsc` runs in
`noEmit` mode purely for strict type-checking and editor IntelliSense.

## Testing

### Prerequisites
Expand Down Expand Up @@ -180,31 +227,48 @@ tests/
│ └── WpunitTester.php # Codeception actor
├── wpunit.suite.dist.yml # Suite configuration (WPLoader module)
└── wpunit/
├── _bootstrap.php # Suite-level bootstrap
├── ConfigTest.php # Config class tests
├── DirectorySyncTest.php # Directory sync tests
├── EntitlementGateTest.php # Entitlement gate tests
├── EventLoggerTest.php # Activity log event logger tests
├── LoginBypassTest.php # Login bypass tests
├── LoginLogoutTest.php # Login logout session revocation tests
├── LoginSessionTest.php # Login session tests
├── LoginTokensTest.php # Login tokens tests
├── LogoutRedirectTest.php # Logout redirect tests
├── OnboardingSyncTest.php # Onboarding sync tests
├── OptionsTest.php # Options classes tests
├── OrganizationManagerTest.php # Organization manager tests
├── PasswordResetTest.php # Password reset tests
├── PluginTest.php # Plugin singleton + constants tests
├── RedirectTest.php # Login redirect tests
├── RoleMapperTest.php # Role mapper tests
├── SchemaTest.php # Database schema tests
├── UserSyncDeprovisionTest.php # User deprovisioning tests
├── UserSyncFindOrCreateTest.php # User find-or-create tests
├── UserSyncLinkTest.php # User linking tests
├── UserSyncPushTest.php # Outbound user sync tests
├── UserSyncResyncTest.php # User re-sync tests
├── WebhookReceiverTest.php # Webhook receiver tests
└── WebhookSignatureTest.php # Webhook signature verification tests
├── _bootstrap.php # Suite-level bootstrap
├── ApiClientAuthKitTest.php # Api\Client Custom-AuthKit methods (magic, totp, reset, mfa, invitation grant, refresh)
├── AuthKitLoginCompleterMfaTest.php # Profile MFA policy enforcement (enforce=always, factor allowlist)
├── AuthKitLoginProfilesRestApiTest.php # /wp-json/workos/v1/admin/profiles CRUD
├── AuthKitNonceTest.php # Profile-scoped nonce mint/verify
├── AuthKitProfileRepositoryTest.php # Profile CRUD, default seeding, slug uniqueness
├── AuthKitProfileRouterTest.php # Rule matching (redirect_to / referrer_host / user_role)
├── AuthKitProfileTest.php # Profile value object + enum validation
├── AuthKitRadarTest.php # Radar site-key resolution + header extraction
├── AuthKitRateLimiterTest.php # Fixed-window IP + email bucket limits
├── AuthKitRendererTest.php # Renderer markup + shortcode + takeover hook wiring
├── AuthKitRestMagicSessionTest.php # magic/{send,verify}, session/{refresh,logout}, /nonce
├── AuthKitRestMfaTest.php # mfa/{challenge,verify,factors,*/enroll,factor/delete}
├── AuthKitRestPasswordTest.php # password/{authenticate,reset/start,reset/confirm}
├── AuthKitRestSignupInvitationOAuthTest.php # signup/{create,verify}, invitation/{token,accept}, oauth/authorize-url
├── ConfigTest.php # Config class tests
├── DirectorySyncTest.php # Directory sync tests
├── EntitlementGateTest.php # Entitlement gate tests
├── EventLoggerTest.php # Activity log event logger tests
├── LoginBypassTest.php # Login bypass tests
├── LoginLogoutTest.php # Login logout session revocation tests
├── LoginSessionTest.php # Login session tests
├── LoginTokensTest.php # Login tokens tests
├── LogoutRedirectTest.php # Logout redirect tests
├── OnboardingSyncTest.php # Onboarding sync tests
├── OptionsTest.php # Options classes tests
├── OrganizationManagerTest.php # Organization manager tests
├── PasswordResetTest.php # Password reset tests
├── PluginTest.php # Plugin singleton + constants tests
├── RedirectTest.php # Login redirect tests
├── RendererKsesTest.php # Shared renderer KSES allowlist tests
├── RoleMapperTest.php # Role mapper tests
├── SchemaTest.php # Database schema tests
├── TokenAuthRefreshTest.php # TokenAuth regression: rejects unsigned/expired Bearer JWTs
├── UserHelperTest.php # WorkOS\User + `workos_is_sso_user`/`workos_has_active_session` helpers
├── UserSyncDeprovisionTest.php # User deprovisioning tests
├── UserSyncFindOrCreateTest.php # User find-or-create tests
├── UserSyncLinkTest.php # User linking tests
├── UserSyncPushTest.php # Outbound user sync tests
├── UserSyncResyncTest.php # User re-sync tests
├── WebhookReceiverTest.php # Webhook receiver tests
└── WebhookSignatureTest.php # Webhook signature verification tests
```

### Writing Tests
Expand Down
Loading