fix(admin): forward cookies in SSR for admin/clubs endpoints
continuous-integration/drone/push Build is passing Details

Root cause: Next.js server-side rendering was making API calls without
forwarding browser cookies, causing AUTHORIZATION_ERROR during page load.

Changes:
- Updated getAdminClubs() to accept optional cookieHeader parameter
- Updated getAdminClubDetail() to accept optional cookieHeader parameter
- Modified /admin/clubs page to extract cookies via next/headers and
  forward them to API calls during SSR
- Use credentials: 'omit' when manually setting Cookie header to avoid
  fetch() conflicts

Result: Admin endpoints now authenticate properly during SSR, allowing
page to render club list correctly instead of showing error state.

Resolves: SSR authorization error reported in BUILD:283 regression test
master
Guillermo Pages 1 month ago
parent ca2a1a8f88
commit 51a928c1f4

@ -3,13 +3,18 @@ import { getTranslate } from '../../dictionaries';
import { Building, AlertCircle, Lock } from 'lucide-react'; import { Building, AlertCircle, Lock } from 'lucide-react';
import { getAdminClubs } from '@/src/lib/api/admin-clubs'; import { getAdminClubs } from '@/src/lib/api/admin-clubs';
import Link from 'next/link'; import Link from 'next/link';
import { cookies } from 'next/headers';
export default async function AdminClubsPage({ params }: { params: Promise<{ locale: Locale }>}) { export default async function AdminClubsPage({ params }: { params: Promise<{ locale: Locale }>}) {
const { locale } = await params; const { locale } = await params;
const {t} = await getTranslate(locale); const {t} = await getTranslate(locale);
// Get cookies for SSR auth
const cookieStore = await cookies();
const cookieHeader = cookieStore.toString();
// Fetch clubs from API - this will handle auth states via HTTP status codes // Fetch clubs from API - this will handle auth states via HTTP status codes
const result = await getAdminClubs(); const result = await getAdminClubs(cookieHeader);
// Handle authentication error (401) // Handle authentication error (401)
if (!result.success && result.error.status === 401) { if (!result.success && result.error.status === 401) {

@ -62,16 +62,24 @@ async function handleApiResponse<T>(response: Response): Promise<AdminApiResult<
* GET /admin/clubs * GET /admin/clubs
* Lists all clubs the authenticated user can manage * Lists all clubs the authenticated user can manage
* *
* @param cookieHeader - Optional cookie header to forward (for SSR)
* @returns Array of clubs or error * @returns Array of clubs or error
*/ */
export async function getAdminClubs(): Promise<AdminApiResult<AdminClubsResponse>> { export async function getAdminClubs(cookieHeader?: string): Promise<AdminApiResult<AdminClubsResponse>> {
try { try {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// Forward cookies for server-side rendering
if (cookieHeader) {
headers['Cookie'] = cookieHeader;
}
const response = await fetch(`${API_BASE_URL}/admin/clubs`, { const response = await fetch(`${API_BASE_URL}/admin/clubs`, {
method: 'GET', method: 'GET',
headers: { headers,
'Content-Type': 'application/json', credentials: cookieHeader ? 'omit' : 'include', // Use 'omit' when manually setting Cookie header
},
credentials: 'include', // Include cookies for auth
}); });
return handleApiResponse<AdminClubsResponse>(response); return handleApiResponse<AdminClubsResponse>(response);
@ -95,18 +103,27 @@ export async function getAdminClubs(): Promise<AdminApiResult<AdminClubsResponse
* Gets detailed information about a specific club * Gets detailed information about a specific club
* *
* @param clubId - The club ID to fetch * @param clubId - The club ID to fetch
* @param cookieHeader - Optional cookie header to forward (for SSR)
* @returns Club details or error * @returns Club details or error
*/ */
export async function getAdminClubDetail( export async function getAdminClubDetail(
clubId: number clubId: number,
cookieHeader?: string
): Promise<AdminApiResult<AdminClubDetail>> { ): Promise<AdminApiResult<AdminClubDetail>> {
try { try {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
// Forward cookies for server-side rendering
if (cookieHeader) {
headers['Cookie'] = cookieHeader;
}
const response = await fetch(`${API_BASE_URL}/admin/clubs/${clubId}`, { const response = await fetch(`${API_BASE_URL}/admin/clubs/${clubId}`, {
method: 'GET', method: 'GET',
headers: { headers,
'Content-Type': 'application/json', credentials: cookieHeader ? 'omit' : 'include', // Use 'omit' when manually setting Cookie header
},
credentials: 'include', // Include cookies for auth
}); });
return handleApiResponse<AdminClubDetail>(response); return handleApiResponse<AdminClubDetail>(response);

Loading…
Cancel
Save