'crewli_app_token', 'portal' => 'crewli_portal_token', ]; private const COOKIE_TTL_MINUTES = 60 * 24 * 7; // 7 days protected function resolveCookieName(Request $request): string { $origin = $request->headers->get('Origin') ?? $request->headers->get('Referer') ?? ''; $appUrl = config('app.frontend_app_url', 'http://localhost:5174'); $portalUrl = config('app.frontend_portal_url', 'http://localhost:5175'); if ($this->originMatches($origin, $appUrl)) { return self::COOKIE_MAP['app']; } if ($this->originMatches($origin, $portalUrl)) { return self::COOKIE_MAP['portal']; } return self::COOKIE_MAP['app']; } protected function makeAuthCookie(string $cookieName, string $token): Cookie { return new Cookie( name: $cookieName, value: $token, expire: now()->addMinutes(self::COOKIE_TTL_MINUTES), path: '/', domain: config('session.domain'), secure: config('app.env') === 'production', httpOnly: true, sameSite: 'Strict', ); } protected function forgetAuthCookie(string $cookieName): Cookie { return new Cookie( name: $cookieName, value: '', expire: now()->subMinute(), path: '/', domain: config('session.domain'), secure: config('app.env') === 'production', httpOnly: true, sameSite: 'Strict', ); } private function originMatches(string $origin, string $configuredUrl): bool { if ($origin === '' || $configuredUrl === '') { return false; } // Parse to compare host+port, ignoring trailing slashes and paths $originHost = parse_url($origin, PHP_URL_HOST); $originPort = parse_url($origin, PHP_URL_PORT); $configHost = parse_url($configuredUrl, PHP_URL_HOST); $configPort = parse_url($configuredUrl, PHP_URL_PORT); return $originHost === $configHost && $originPort === $configPort; } }