[6.x] Refactor Authentication front-end#18800
Conversation
It's probably not a bad thing, but having the classname in the URL felt dirty to me
…eature/inertia-auth
Converts LoginForm.js (Garnish-based) into a self-contained LitElement web component in the @craftcms/cp package. Handles login, reset-password, and 2FA views; supports passkeys via @simplewebauthn/browser; dispatches a craft-login event on success for modal embedding. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- craft-login-form: slim orchestrator — login view, passkey, view routing - craft-login-reset-password: self-contained reset-password form, fires reset-back - craft-login-2fa: renders and initialises server-side 2FA form, handles method switching Components communicate via custom events (reset-back, login-success, login-error). TwoFactorData interface exported from login-2fa for shared typing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
craft-totp-form and craft-recovery-code-form replace the Garnish-based auth form handlers. Both render their own UI with craft-input and craft-button, auto-submit on complete input, and fire login-success / login-error events. craft-login-2fa now renders these directly via WEB_COMPONENT_METHODS lookup when the authMethod matches, falling back to Craft.createAuthFormHandler for any legacy server-rendered form that isn't covered yet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Just the first pass, more refinement to come
|
|
||
| if ($user) { | ||
| Session::put('user.id', $user->id); | ||
| Session::put('user.pending_2fa_at', now()->timestamp); |
There was a problem hiding this comment.
The 2fa session was previously lasting as long as a regular session. This creates a lil' 5 minute session for completing the 2fa flow
There was a problem hiding this comment.
This will eventually take over for Pane.vue
|
|
||
| public function setupHtml(Request $request, HtmlStack $HtmlStack): JsonResponse | ||
| { | ||
| Session::put('user.pending_2fa_at', now()->timestamp); |
There was a problem hiding this comment.
With a short 2fa session, we need to start one to give you some time between when we show the setup HTML and when you confirm your 2fa method. Without starting a session here (and with the short 2fa session time) you're not able to set up a new auth method.
I think this is safe because this controller is behind the auth:craft middleware, but if this seems like a bad idea I'm open to suggestions.
We can also ditch the idea of opening a short session for finishing the 2fa process but I do feel like it's probably a good idea not to allow you to finish the 2fa process anytime during your (potentially long) session.
Refactors the LoginForm.js file into a web component. Step one in a bit of a larger plan. For now, this replaces most of the code within
_special/login.twigwith a newcraft-login-formweb component. That web component handles the whole of the auth flow. It will submit the username/password, display a two factor challenge and pass you on to the return configured return URL.Eventually, I'd like to make this web component available to front-end requests so users can just throw a
<craft-login-form/>into their templates and get the whole login flow.How it works
The general flow hasn't changed from the previous LoginForm.js file. The auth flow is made up of three parts. There's the main login form, the password reset form, and the 2fa challenge form (when applicable). In this implementation these are three separate components that communicate with each other via some internal events.
After the initial login, the LoginController will return a JSON object that includes the HTML for the next stage's auth form along with some other data. The full data shape is represented by the
TwoFactorDatatypescript type.When data is return with
authMethodthe challenge form is also shown. A successful challenge will eventually emit acraft:login:successevent you can listen for in order to act accordingly. I'm still working out / thinking about how to handle events globally in the system, so this may very well change.By default, this will redirect you to the
returnUrlbut the event is cancelable so you can handle it as you see fit. For example, within our elevated session manager we prevent the default and just close the modal.This PR also removes the idea of an auth handler in favor of listening for events directly. Components that extend the
AuthChallengeFormcomponent will emit alogin-verifiedevent you can listen to in order to act on this part of the process. For example, within the auth setup of TOTP we use this to close the modal after a successful verificationWe recommend extending this
CraftAuthChallengeFormbase component in order to create your own challenge forms that will follow the convention of ours. Both the TOTP and RecoveryCode forms extend this base component as examples.Note
All code related to the
TotpAssetand theRecoveryCodesAssethas been moved into the yii2-adapter and removed from the main codebase.