1---2name: tyro-login3description: Laravel authentication infrastructure package providing guards, providers, sessions, tokens, verification, and security for the Tyro ecosystem.4---56# Tyro Login Skill78This is a **framework-maintainer** skill for the `hasinhayder/tyro-login` authentication package.910It teaches AI models how to create, review, refactor, and maintain Tyro Login with the mindset of a framework maintainer — protecting public APIs, preserving backward compatibility, and designing for ecosystem growth over a 10+ year maintenance horizon.1112This is NOT an application-development skill.13This is NOT a login page generator.14This is NOT a starter kit.15This is authentication infrastructure.1617---1819## Activation Triggers2021The skill activates when any of these patterns appear in the task context:2223### File Paths2425```26src/**/*.php27config/tyro-login.php28routes/web.php29resources/views/**/*.blade.php30database/migrations/*.php31tests/**/*.php32composer.json33skills/tyro-login/**34```3536### Class References3738```39HasinHayder\TyroLogin\*40HasinHayder\TyroLogin\Providers\TyroLoginServiceProvider41HasinHayder\TyroLogin\Http\Controllers\*42HasinHayder\TyroLogin\Models\*43HasinHayder\TyroLogin\Console\Commands\*44HasinHayder\TyroLogin\Mail\*45HasinHayder\TyroLogin\Casts\EncryptedOrPlaintext46HasinHayder\TyroLogin\Traits\HasTwoFactorAuth47HasinHayder\TyroLogin\Helpers\InvitationHelper48```4950### Config and Environment Keys5152```53config('tyro-login.*')54env('TYRO_LOGIN_*')55```5657---5859## Consistency First6061Eight immutable principles that govern every decision in this package:6263| # | Principle | Rationale |64|---|---|---|65| 1 | **Config-first design** | Every feature must be toggleable via config. Never hardcode behavior. |66| 2 | **Cache over database for transient state** | OTP codes, lockout counters, password reset tokens, magic links, verification tokens — all use cache, not the database. |67| 3 | **Soft integration for optional packages** | Use `class_exists()` and `method_exists()` at runtime. Never add optional packages to `require` in composer.json. |68| 4 | **Backward compatible encryption** | New data is encrypted. Legacy data is read as plaintext and encrypted on write. The `EncryptedOrPlaintext` cast handles this transition. |69| 5 | **POST-only state mutations** | Login, logout, register, OTP verification, 2FA confirmation, password updates — all require POST. No GET mutations. |70| 6 | **Session regeneration on auth transitions** | Every authentication boundary transition — login, logout, OTP step-up, 2FA step-up — must regenerate the session ID. |71| 7 | **Configurable User Model everywhere** | Never reference `App\Models\User` directly. Always use `config('tyro-login.user_model')` in relationships, traits, and providers. |72| 8 | **Environment-driven defaults** | Every config value must read from an environment variable with a sensible default. The config file is the single source of truth; controllers never call `env()` directly. |7374---7576## Quick Reference7778### File Map7980| File | Purpose |81|---|---|82| `src/Providers/TyroLoginServiceProvider.php` | Package bootstrap — config merge, route registration, view loading, migration loading, publish commands, auth redirection |83| `src/Http/Controllers/LoginController.php` | Login form, authenticate, lockout, OTP flow, magic links, logout |84| `src/Http/Controllers/RegisterController.php` | Registration form, user creation, captcha, password validation, Tyro role assignment |85| `src/Http/Controllers/TwoFactorController.php` | TOTP setup, QR code generation, TOTP verification, recovery codes, 2FA challenge |86| `src/Http/Controllers/VerificationController.php` | Email verification notice, token generation, verification, resend |87| `src/Http/Controllers/PasswordResetController.php` | Forgot password form, reset link generation, password reset |88| `src/Http/Controllers/SocialAuthController.php` | OAuth redirect, callback, social user linking, auto-registration |89| `src/Models/SocialAccount.php` | OAuth provider account linked to user |90| `src/Models/InvitationLink.php` | Referral link for invitation system |91| `src/Models/InvitationReferral.php` | Referral tracking record |92| `src/Casts/EncryptedOrPlaintext.php` | Eloquent cast — reads encrypted or legacy plaintext, always writes encrypted |93| `src/Traits/HasTwoFactorAuth.php` | User model trait — 2FA casts and helper methods |94| `src/Helpers/InvitationHelper.php` | Static utility for invitation validation and referral tracking |95| `src/Mail/OtpMail.php` | One-time password email |96| `src/Mail/PasswordResetMail.php` | Password reset email |97| `src/Mail/VerifyEmailMail.php` | Email verification email |98| `src/Mail/WelcomeMail.php` | Welcome email after registration |99| `src/Mail/MagicLinkMail.php` | Magic link login email |100| `config/tyro-login.php` | Package configuration (631 lines, all env-controllable) |101| `routes/web.php` | All authentication route definitions |102| `database/migrations/*.php` | Schema migrations for social accounts, 2FA columns, invitation system |103104### Config Key Index105106| Key Group | Env Prefix | Description |107|---|---|---|108| `tyro-login.debug` | `TYRO_LOGIN_DEBUG` | Enables sensitive debug logging |109| `tyro-login.layout` | `TYRO_LOGIN_LAYOUT` | View layout — centered, split-left, split-right, fullscreen, card |110| `tyro-login.branding.*` | `TYRO_LOGIN_*` | App name, logo, logo_dark, logo_height |111| `tyro-login.routes.*` | — | Route prefix, middleware, name overrides |112| `tyro-login.redirects.*` | — | Post-login/logout/register/verification redirects |113| `tyro-login.registration.*` | `TYRO_LOGIN_REGISTRATION_*` | Registration enabled, auto_login, require_email_verification |114| `tyro-login.tyro.*` | — | Tyro package integration (role assignment) |115| `tyro-login.user_model` | — | Customizable User model class |116| `tyro-login.features.*` | `TYRO_LOGIN_FEATURE_*` | Feature toggles — remember_me, forgot_password, magic_links, disable_password |117| `tyro-login.password.*` | — | Password policy — min/max length, complexity, common password check |118| `tyro-login.login_field` | — | Login field — email, username, or both |119| `tyro-login.pages.*` | — | Per-page content — titles, subtitles, background copy |120| `tyro-login.verification.*` | — | Token expiration in minutes |121| `tyro-login.password_reset.*` | — | Token expiration in minutes |122| `tyro-login.captcha.*` | — | Math captcha settings per form |123| `tyro-login.otp.*` | — | OTP settings — length, expire, resend limits |124| `tyro-login.two_factor.*` | — | TOTP 2FA — setup, challenge, forced roles, ignore cookie |125| `tyro-login.emails.*` | — | Per-email-type enable/subject configuration |126| `tyro-login.social.*` | — | OAuth providers — 8 providers with per-provider settings |127| `tyro-login.lockout.*` | — | Brute-force protection — max_attempts, duration, show_attempts_left |128129### Route Name Index130131| Route Name | Method | URI | Controller | Purpose |132|---|---|---|---|---|133| `tyro-login.login` | GET | `login` | LoginController@showLoginForm | Display login form |134| `tyro-login.login` | POST | `login` | LoginController@login | Submit login |135| `tyro-login.logout` | GET/POST | `logout` | LoginController@logout | Logout (POST only processes) |136| `tyro-login.register` | GET | `register` | RegisterController@showRegistrationForm | Display registration form |137| `tyro-login.register` | POST | `register` | RegisterController@register | Submit registration |138| `tyro-login.password.request` | GET | `password/reset` | PasswordResetController@showForgotPasswordForm | Forgot password form |139| `tyro-login.password.email` | POST | `password/reset` | PasswordResetController@sendResetLink | Send reset link |140| `tyro-login.password.reset` | GET | `password/reset/{token}` | PasswordResetController@showResetForm | Display reset form |141| `tyro-login.password.update` | POST | `password/reset/{token}` | PasswordResetController@reset | Submit new password |142| `tyro-login.verification.notice` | GET | `email/verify` | VerificationController@showVerificationNotice | Verification notice |143| `tyro-login.verification.verify` | GET | `email/verify/{id}/{hash}` | VerificationController@verify | Verify email |144| `tyro-login.verification.resend` | POST | `email/verification-notification` | VerificationController@resend | Resend verification |145| `tyro-login.verification.not-verified` | GET | `email/not-verified` | VerificationController@showEmailNotVerified | Not-verified notice |146| `tyro-login.otp.form` | GET | `otp/verify` | LoginController@showOtpForm | OTP input form |147| `tyro-login.otp.verify` | POST | `otp/verify` | LoginController@verifyOtp | Verify OTP code |148| `tyro-login.otp.resend` | POST | `otp/resend` | LoginController@resendOtp | Resend OTP |149| `tyro-login.otp.cancel` | POST | `otp/cancel` | LoginController@cancelOtp | Cancel OTP flow |150| `tyro-login.2fa.challenge` | GET | `2fa/challenge` | TwoFactorController@showChallenge | 2FA challenge form |151| `tyro-login.2fa.verify` | POST | `2fa/challenge` | TwoFactorController@verify | Verify 2FA code |152| `tyro-login.2fa.setup` | GET | `2fa/setup` | TwoFactorController@showSetup | 2FA setup page |153| `tyro-login.2fa.confirm` | POST | `2fa/setup` | TwoFactorController@confirm | Confirm TOTP setup |154| `tyro-login.2fa.skip` | POST | `2fa/skip` | TwoFactorController@skip | Skip 2FA setup |155| `tyro-login.2fa.ignore` | POST | `2fa/ignore` | TwoFactorController@ignore | Ignore 2FA with cookie |156| `tyro-login.2fa.recovery-codes` | GET | `2fa/recovery-codes` | TwoFactorController@showRecoveryCodes | Display recovery codes |157| `tyro-login.social.redirect` | GET | `login/{provider}` | SocialAuthController@redirect | OAuth provider redirect |158| `tyro-login.social.callback` | GET | `login/{provider}/callback` | SocialAuthController@callback | OAuth callback |159| `tyro-login.magic-link.request` | POST | `magic-link` | LoginController@requestMagicLink | Request magic link |160| `tyro-login.magic-link.login` | GET | `magic-link/{token}` | LoginController@magicLogin | Login via magic link |161| `tyro-login.lockout` | GET | `lockout` | LoginController@showLockout | Lockout page |162163### Command Index164165| Signature | Description |166|---|---|167| `tyro-login:install` | Full installation wizard |168| `tyro-login:publish` | Publish specific resources |169| `tyro-login:publish-style` | Publish shadcn theme or styles |170| `tyro-login:update-config` | Refresh config with latest defaults |171| `tyro-login:update-style` | Update published styles |172| `tyro-login:version` | Show version information |173| `tyro-login:doc` | Open documentation in browser |174| `tyro-login:star` | Open GitHub to star the repo |175| `tyro-login:verify-user` | Manually verify a user's email |176| `tyro-login:unverify-user` | Remove email verification |177| `tyro-login:reset-2fa` | Reset two-factor authentication |178| `tyro-login:magic-links` | Manage magic links (create, list, remove, flush) |179| `tyro-login:invite-links` | Manage invitation links (create, list, remove, flush) |180| `tyro-login:setup-ai-skill` | Install the Tyro Login AI skill for a chosen agent (Claude, Copilot, Codex, Gemini, Kilo, Laravel Boost, or all) with universal agents.md support |181182### Environment Variable Index183184| Env Var | Config Key | Type | Default |185|---|---|---|---|186| `TYRO_LOGIN_DEBUG` | `tyro-login.debug` | `bool` | `false` |187| `TYRO_LOGIN_LAYOUT` | `tyro-login.layout` | `string` | `'centered'` |188| `TYRO_LOGIN_APP_NAME` | `tyro-login.branding.app_name` | `string` | `env('APP_NAME', 'Tyro Login')` |189| `TYRO_LOGIN_REGISTRATION_ENABLED` | `tyro-login.registration.enabled` | `bool` | `true` |190| `TYRO_LOGIN_FEATURE_REMEMBER_ME` | `tyro-login.features.remember_me` | `bool` | `true` |191| `TYRO_LOGIN_FEATURE_FORGOT_PASSWORD` | `tyro-login.features.forgot_password` | `bool` | `true` |192| `TYRO_LOGIN_FEATURE_MAGIC_LINKS` | `tyro-login.features.magic_links_enabled` | `bool` | `false` |193| `TYRO_LOGIN_FEATURE_DISABLE_PASSWORD` | `tyro-login.features.disable_password` | `bool` | `false` |194| `TYRO_LOGIN_LOGIN_FIELD` | `tyro-login.login_field` | `string` | `'email'` |195| `TYRO_LOGIN_OTP_LENGTH` | `tyro-login.otp.length` | `int` | `6` |196| `TYRO_LOGIN_OTP_EXPIRE` | `tyro-login.otp.expire` | `int` | `10` |197| `TYRO_LOGIN_LOCKOUT_MAX_ATTEMPTS` | `tyro-login.lockout.max_attempts` | `int` | `5` |198| `TYRO_LOGIN_LOCKOUT_DURATION` | `tyro-login.lockout.duration` | `int` | `60` |199200---201202## Rule Files203204| Tier | File | Covers |205|---|---|---|206| 0 | [rules/framework-mindset.md](rules/framework-mindset.md) | Framework-maintainer philosophy — the foundational decision-making framework for every rule below |207| 0 | [rules/security.md](rules/security.md) | Session protection, credential handling, rate limiting, CSRF, encryption, lockout |208| 0 | [rules/two-factor.md](rules/two-factor.md) | TOTP setup, verification, recovery codes, 2FA challenge flow, dual-cast-aware methods |209| 1 | [rules/service-provider.md](rules/service-provider.md) | Package lifecycle — register, boot, publishing, auto-discovery |210| 1 | [rules/routes.md](rules/routes.md) | Route definitions, middleware groups, naming conventions |211| 1 | [rules/models-and-casts.md](rules/models-and-casts.md) | Data layer — Eloquent models, relationships, EncryptedOrPlaintext cast, HasTwoFactorAuth trait |212| 1 | [rules/social-login.md](rules/social-login.md) | OAuth provider redirect, callback, social user linking, auto-registration, email verification |213| 1 | [rules/suspension.md](rules/suspension.md) | User suspension checks on login, social auth, and magic link flows |214| 2 | [rules/config-and-env.md](rules/config-and-env.md) | Config file structure, env var protocol, type casting, documentation |215| 2 | [rules/controllers.md](rules/controllers.md) | Controller patterns, validation, responses, multi-step auth flows, view data convention |216| 2 | [rules/mailables.md](rules/mailables.md) | Mailable classes, email templates, queueing, toggleable emails |217| 2 | [rules/email-templates.md](rules/email-templates.md) | Email Blade template structure, design conventions, email preview |218| 2 | [rules/commands.md](rules/commands.md) | Artisan command patterns, user lookup, interactive prompts |219| 2 | [rules/views-and-themes.md](rules/views-and-themes.md) | View structure, layout system, shadcn theme, view publishing |220| 2 | [rules/otp.md](rules/otp.md) | One-time password generation, delivery, verification, and resend limits |221| 2 | [rules/magic-login.md](rules/magic-login.md) | Magic link token generation, delivery, redemption, and expiration |222| 2 | [rules/captcha.md](rules/captcha.md) | Math captcha generation, session storage, per-form configuration, validation |223| 2 | [rules/invitation.md](rules/invitation.md) | Invitation links, referral tracking, self-referral prevention, InvitationHelper |224| 2 | [rules/password-policy.md](rules/password-policy.md) | Password complexity, common passwords, user-info disallowal, confirmation |225| 2 | [rules/registration.md](rules/registration.md) | Registration flow, auto-login, role assignment, post-registration branching |226| 2 | [rules/verification.md](rules/verification.md) | Email verification tokens, signed URLs, cache storage, resend logic |227| 2 | [rules/password-reset.md](rules/password-reset.md) | Password reset tokens, signed URLs, cache storage, user enumeration prevention |228| 3 | [rules/integration-boundaries.md](rules/integration-boundaries.md) | Soft dependencies, Tyro integration, Socialite, backward compatibility, deprecation |229230---231232## How to Apply2332341. **Identify the scope** — Determine which component(s) the task touches (controllers, models, config, routes, etc.)2352. **Load the relevant rule files** — Read the rule files for the affected components2363. **Apply tier 0 rules first** — Framework mindset and security rules always take precedence2374. **Check cross-references** — Rules reference related rules when concerns overlap (e.g., controllers → security, models → backward compatibility)2385. **Validate against existing patterns** — The codebase itself is the source of truth; rules codify existing patterns, they do not invent new ones2396. **When rules conflict** — Lower-numbered tier wins; within a file, earlier rules take precedence