# Profile Direct Login Feature ## Overview This feature allows you to create direct links to User, Organization, Bank, and Admin profile logins that can be used in emails or other external communications. The system handles the authentication flow automatically for all profile types, with automatic username pre-filling for better user experience. ## How It Works The direct login route implements a secure, multi-step authentication flow: 1. **User Authentication Check** - If the user is not logged in with their personal User profile, they are redirected to the user login page - **For User profiles**: Username is automatically pre-filled on the login form via URL parameter - After successful user login, they are automatically redirected back to continue the profile switch flow 2. **Relationship Verification** - The system verifies that the authenticated user has access to the specified profile: - **User**: Authenticated user must match the target user - **Organization**: User owns/is a member of the organization - **Bank**: User manages the bank - **Admin**: User has this admin profile - If the user doesn't have access, a 403 Forbidden error is returned 3. **Profile Switch** - **User**: Direct redirect to main page (or custom intended URL) - **Organization**: Direct switch without password (matches normal profile switching behavior) - **Bank**: Redirected to bank password entry page - **Admin**: Redirected to admin password entry page 4. **Final Redirect** - **User**: Redirected to intended URL or main page - **Organization/Bank/Admin**: Redirected to intended URL or main page after profile switch ## Usage ### User Profile To create a link to a user login: ```php route('user.direct-login', ['userId' => $user->id]) ``` **Example URL:** ``` https://yoursite.com/user/123/login ``` With custom intended destination (e.g., profile edit) and username pre-fill: ```php route('user.direct-login', [ 'userId' => $user->id, 'intended' => route('profile.edit'), 'name' => $user->name // Optional: pre-fills username on login form ]) ``` **Example URL with username pre-fill:** ``` https://yoursite.com/nl/user/123/login?intended=https%3A%2F%2Fyoursite.com%2Fnl%2Fprofiel%2Fbewerken&name=johndoe ``` **Note:** - User direct login defaults to redirecting to the main page after login, but you can override this with the `intended` parameter - The `name` parameter is automatically included when generating links via `ProfileEditedByAdminMail` for improved user experience - When the user is redirected to the login page, the username field will be automatically pre-filled with the value from the `name` parameter ### Organization Profile To create a link to an organization login: ```php route('organization.direct-login', ['organizationId' => $organization->id]) ``` **Example URL:** ``` https://yoursite.com/organization/123/login ``` With intended destination: ```php route('organization.direct-login', [ 'organizationId' => $organization->id, 'intended' => route('organization.settings') ]) ``` ### Bank Profile To create a link to a bank login: ```php route('bank.direct-login', ['bankId' => $bank->id]) ``` **Example URL:** ``` https://yoursite.com/bank/456/login ``` With intended destination: ```php route('bank.direct-login', [ 'bankId' => $bank->id, 'intended' => route('transactions.review') ]) ``` ### Admin Profile To create a link to an admin login: ```php route('admin.direct-login', ['adminId' => $admin->id]) ``` **Example URL:** ``` https://yoursite.com/admin/789/login ``` With intended destination: ```php route('admin.direct-login', [ 'adminId' => $admin->id, 'intended' => route('admin.dashboard') ]) ``` ### In Email Templates ```blade Login to {{ $organization->name }} ``` Or with a specific destination: ```blade Edit this post as {{ $organization->name }} ``` ## Security Features ### Multi-Layer Authentication - **User Guard First**: Ensures base authentication is established - **Relationship Verification**: Only users with proper access can switch to the organization - **Password Re-Authentication**: Separate password required for organization access ### Session Management - Profile switch intent is stored in encrypted session - Intended URLs are validated and sanitized - Sessions are cleared after successful authentication ### Access Control - 404 error if organization doesn't exist - 403 error if user doesn't have access to organization - All authentication follows the existing SwitchGuardTrait security pattern ## Flow Diagram ``` User clicks email link | v Is user authenticated? --NO--> User Login --> [Back to this flow] | YES v Does user own/manage org? --NO--> 403 Forbidden | YES v Set profile switch intent | v Organization password page | v Password correct? --NO--> Error message | YES v Switch to Organization guard | v Redirect to intended URL or main page ``` ## Implementation Details ### Route Definitions Located in `routes/web.php`: **User Route (Guest accessible - no auth middleware):** ```php // Located in the guest routes section (line ~182) // Accessible to both authenticated and non-authenticated users Route::get('/user/{userId}/login', [UserLoginController::class, 'directLogin']) ->name('user.direct-login'); ``` **Organization/Bank/Admin Routes (Inside auth middleware group):** ```php // Located inside the auth middleware group (line ~439+) // Require user authentication before accessing Route::get('/organization/{organizationId}/login', [OrganizationLoginController::class, 'directLogin']) ->name('organization.direct-login'); Route::get('/bank/{bankId}/login', [BankLoginController::class, 'directLogin']) ->name('bank.direct-login'); Route::get('/admin/{adminId}/login', [AdminLoginController::class, 'directLogin']) ->name('admin.direct-login'); ``` **Important:** The user route is placed in the guest routes section (outside auth middleware) to allow unauthenticated users to access it. The controller handles authentication checks internally and redirects to login when needed. ### Controller Methods Located in: - `app/Http/Controllers/UserLoginController.php` - `app/Http/Controllers/OrganizationLoginController.php` - `app/Http/Controllers/BankLoginController.php` - `app/Http/Controllers/AdminLoginController.php` Each `directLogin()` method handles: - Profile existence validation - User authentication check - Relationship verification: - **User**: Authenticated user must match target user - **Organization**: User owns/is a member of the organization - **Bank**: User manages the bank - **Admin**: User has this admin profile - Session intent setting (for Organization, Bank, Admin) - Proper redirects for each step **User-specific features:** - **Username Pre-fill**: When redirecting to login, the `name` query parameter is preserved and passed to the login page - **Localized URLs**: Uses `LaravelLocalization` to generate properly localized redirect URLs - **URL Parameter Handling**: The `name` parameter from the direct login URL is forwarded to the login page as a query parameter - The login form reads the `name` parameter via `request()->input('name')` and pre-fills the username field ### Login Form Implementation The login form in `resources/views/auth/login.blade.php` supports username pre-filling via URL parameter: ```blade
@csrf
``` **Key points:** - The `value` attribute uses `old('name', request()->input('name'))` to: 1. First check for validation errors (old input) 2. Fall back to the URL query parameter if no old input exists - The `autocomplete="username"` attribute helps browsers identify the field correctly - This works for direct URL access (e.g., `/nl/inloggen?name=johndoe`) as well as redirects ### Session Keys Used **For all profile types:** - `url.intended`: Laravel's standard intended redirect URL (used for user login redirect back to profile login) - `intended_profile_switch_type`: Set to 'Organization', 'Bank', or 'Admin' - `intended_profile_switch_id`: Profile ID **Profile-specific:** - `organization_login_intended_url`: Optional final destination URL after organization login - `bank_login_intended_url`: Optional final destination URL after bank login - `admin_login_intended_url`: Optional final destination URL after admin login ## Examples ### Example 1: Simple Profile Login Links ```php // User $url = route('user.direct-login', ['userId' => 123]); // Result: https://yoursite.com/user/123/login // Organization $url = route('organization.direct-login', ['organizationId' => 5]); // Result: https://yoursite.com/organization/5/login // Bank $url = route('bank.direct-login', ['bankId' => 2]); // Result: https://yoursite.com/bank/2/login // Admin $url = route('admin.direct-login', ['adminId' => 1]); // Result: https://yoursite.com/admin/1/login ``` ### Example 2: Deep Links to Specific Pages ```php // User: Direct link to profile edit page $url = route('user.direct-login', [ 'userId' => $user->id, 'intended' => route('profile.edit') ]); // Organization: Direct link to post management page $url = route('organization.direct-login', [ 'organizationId' => $org->id, 'intended' => route('posts.index') ]); // Bank: Direct link to transaction review $url = route('bank.direct-login', [ 'bankId' => $bank->id, 'intended' => route('transactions.pending') ]); // Admin: Direct link to user management $url = route('admin.direct-login', [ 'adminId' => $admin->id, 'intended' => route('admin.users') ]); ``` ### Example 3: In Blade Email Templates **User Profile Edited Notification (Automated via ProfileEditedByAdminMail):** The `ProfileEditedByAdminMail` class automatically generates properly localized URLs with username pre-fill: ```php // In ProfileEditedByAdminMail.php constructor: $profileEditPath = LaravelLocalization::getURLFromRouteNameTranslated( $this->locale, 'routes.profile.edit' ); $profileEditUrl = url($profileEditPath); // Direct user login with redirect to profile.edit and username pre-filled $this->buttonUrl = LaravelLocalization::localizeURL( route('user.direct-login', [ 'userId' => $profile->id, 'intended' => $profileEditUrl, 'name' => $profile->name // Username pre-fill ]), $this->locale ); ``` **Generated URL example:** ``` https://yoursite.com/nl/user/2/login?intended=https%3A%2F%2Fyoursite.com%2Fnl%2Fprofiel%2Fbewerken&name=johndoe ``` **Email template usage:** ```blade @component('emails.layouts.html', ['locale' => $locale])

Hello {{ $profile->full_name ?? $profile->name }},

An administrator has made changes to your profile.

@endcomponent ``` **Organization Event Review:** ```blade @component('emails.layouts.html', ['locale' => 'en'])

Hello {{ $user->name }},

A new event requires your organization's approval.

@endcomponent ``` **Bank Transaction Alert:** ```blade @component('emails.layouts.html', ['locale' => 'en'])

Hello {{ $user->name }},

A large transaction requires bank approval.

@endcomponent ``` **Admin User Report:** ```blade @component('emails.layouts.html', ['locale' => 'en'])

Hello {{ $user->name }},

A user has been reported and requires admin review.

@endcomponent ``` ## Troubleshooting ### User Gets 404 Error - The profile ID doesn't exist - Check that the profile hasn't been soft-deleted - Verify correct profile type is being used ### User Gets 403 Error - User doesn't have access to the profile - **For User**: Authenticated user ID doesn't match target user ID - **For Organization**: Verify relationship exists in `organization_user` table - **For Bank**: Verify user is listed as manager in `bank_managers` table - **For Admin**: Verify user has this admin profile in `admin_user` table ### Redirect Loop - Ensure user login is working correctly - Check that session storage is configured properly - Verify middleware chain is correct ### Username Not Pre-filled on Login Form - Check that the `name` parameter is included in the direct login URL - Verify the login form is using `request()->input('name')` to read the parameter - Check browser developer tools to confirm the query parameter is present in the URL - Ensure the login view has: `value="{{ old('name', request()->input('name')) }}"` ### User Direct Login Redirects to Login Without Query Parameters **Problem:** Query parameters (`intended` and `name`) are stripped during redirect **Cause:** The user.direct-login route is inside the auth middleware group, which redirects unauthenticated users to login before the controller can handle the parameters **Solution:** Ensure the user.direct-login route is defined in the **guest routes section** of `routes/web.php` (around line 182), NOT inside the auth middleware group. The route should only have localization middleware, not authentication middleware: ```php // ✅ Correct - in guest routes section Route::get('/user/{userId}/login', [UserLoginController::class, 'directLogin']) ->name('user.direct-login'); // ❌ Wrong - inside auth middleware group Route::middleware(['auth:web'])->group(function () { Route::get('/user/{userId}/login', [...]) // Don't place here! }); ``` Verify with: `php artisan route:list --name=user.direct-login -v` The route should show only these middleware: - web - LocaleSessionRedirect - LaravelLocalizationRedirectFilter - LaravelLocalizationViewPath If you see `Authenticate:web` or other auth middleware, the route is in the wrong location. ## Related Documentation - [SECURITY_OVERVIEW.md](SECURITY_OVERVIEW.md) - Complete authentication system documentation - Multi-Guard Authentication System - Profile Switch Flow - Session Security