fix auth
This commit is contained in:
		
							parent
							
								
									27b94edcfa
								
							
						
					
					
						commit
						e8daa37d08
					
				@ -1,5 +1,7 @@
 | 
			
		||||
// src/pages/api/auth/login.ts (ENHANCED - Consistent cookie handling)
 | 
			
		||||
import type { APIRoute } from 'astro';
 | 
			
		||||
import { generateAuthUrl, generateState, logAuthEvent } from '../../../utils/auth.js';
 | 
			
		||||
import { serialize } from 'cookie';
 | 
			
		||||
 | 
			
		||||
export const prerender = false;
 | 
			
		||||
 | 
			
		||||
@ -8,14 +10,28 @@ export const GET: APIRoute = async ({ url, redirect }) => {
 | 
			
		||||
    const state = generateState();
 | 
			
		||||
    const authUrl = generateAuthUrl(state);
 | 
			
		||||
    
 | 
			
		||||
    console.log('Generated auth URL:', authUrl);
 | 
			
		||||
    console.log('[AUTH] Generated auth URL:', authUrl);
 | 
			
		||||
    
 | 
			
		||||
    const returnTo = url.searchParams.get('returnTo') || '/';
 | 
			
		||||
    
 | 
			
		||||
    logAuthEvent('Login initiated', { returnTo, authUrl });
 | 
			
		||||
    
 | 
			
		||||
    const stateData = JSON.stringify({ state, returnTo });
 | 
			
		||||
    const stateCookie = `auth_state=${encodeURIComponent(stateData)}; HttpOnly; SameSite=Lax; Path=/; Max-Age=600`;  
 | 
			
		||||
    
 | 
			
		||||
    // Use consistent cookie serialization (same as session cookies)
 | 
			
		||||
    const publicBaseUrl = process.env.PUBLIC_BASE_URL || '';
 | 
			
		||||
    const isProduction = process.env.NODE_ENV === 'production';
 | 
			
		||||
    const isSecure = publicBaseUrl.startsWith('https://') || isProduction;
 | 
			
		||||
    
 | 
			
		||||
    const stateCookie = serialize('auth_state', stateData, {
 | 
			
		||||
      httpOnly: true,
 | 
			
		||||
      secure: isSecure,
 | 
			
		||||
      sameSite: 'lax',
 | 
			
		||||
      maxAge: 600, // 10 minutes
 | 
			
		||||
      path: '/'
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    console.log('[AUTH] Setting auth state cookie:', stateCookie.substring(0, 50) + '...');
 | 
			
		||||
    
 | 
			
		||||
    return new Response(null, {
 | 
			
		||||
      status: 302,
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
// src/pages/api/auth/process.ts (FIXED - Proper cookie handling)
 | 
			
		||||
// src/pages/api/auth/process.ts (ENHANCED - Proper auth success indication)
 | 
			
		||||
import type { APIRoute } from 'astro';
 | 
			
		||||
import { 
 | 
			
		||||
  verifyAuthState,
 | 
			
		||||
@ -7,7 +7,7 @@ import {
 | 
			
		||||
  createSessionWithCookie,
 | 
			
		||||
  logAuthEvent
 | 
			
		||||
} from '../../../utils/auth.js';
 | 
			
		||||
import { apiError, apiSpecial, apiWithHeaders, handleAPIRequest } from '../../../utils/api.js';
 | 
			
		||||
import { apiError, apiSpecial, handleAPIRequest } from '../../../utils/api.js';
 | 
			
		||||
 | 
			
		||||
export const prerender = false;
 | 
			
		||||
 | 
			
		||||
@ -30,9 +30,15 @@ export const POST: APIRoute = async ({ request }) => {
 | 
			
		||||
    
 | 
			
		||||
    const stateVerification = verifyAuthState(request, state);
 | 
			
		||||
    if (!stateVerification.isValid || !stateVerification.stateData) {
 | 
			
		||||
      logAuthEvent('State verification failed', { 
 | 
			
		||||
        error: stateVerification.error,
 | 
			
		||||
        hasStateData: !!stateVerification.stateData 
 | 
			
		||||
      });
 | 
			
		||||
      return apiError.badRequest(stateVerification.error || 'Invalid state parameter');
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    console.log('[AUTH] State verification successful, exchanging code for tokens');
 | 
			
		||||
    
 | 
			
		||||
    const tokens = await exchangeCodeForTokens(code);
 | 
			
		||||
    const userInfo = await getUserInfo(tokens.access_token);
 | 
			
		||||
    
 | 
			
		||||
@ -43,6 +49,13 @@ export const POST: APIRoute = async ({ request }) => {
 | 
			
		||||
      email: sessionResult.userEmail 
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    // Add auth success indicator to the return URL
 | 
			
		||||
    const returnUrl = new URL(stateVerification.stateData.returnTo, request.url);
 | 
			
		||||
    returnUrl.searchParams.set('auth', 'success');
 | 
			
		||||
    const redirectUrl = returnUrl.toString();
 | 
			
		||||
    
 | 
			
		||||
    console.log('[AUTH] Redirecting to:', redirectUrl);
 | 
			
		||||
    
 | 
			
		||||
    const responseHeaders = new Headers();
 | 
			
		||||
    responseHeaders.set('Content-Type', 'application/json');
 | 
			
		||||
    
 | 
			
		||||
@ -51,7 +64,7 @@ export const POST: APIRoute = async ({ request }) => {
 | 
			
		||||
    
 | 
			
		||||
    return new Response(JSON.stringify({ 
 | 
			
		||||
      success: true, 
 | 
			
		||||
      redirectTo: stateVerification.stateData.returnTo 
 | 
			
		||||
      redirectTo: redirectUrl
 | 
			
		||||
    }), {
 | 
			
		||||
      status: 200,
 | 
			
		||||
      headers: responseHeaders
 | 
			
		||||
 | 
			
		||||
@ -62,24 +62,33 @@ const currentUrl = Astro.url.href;
 | 
			
		||||
<BaseLayout title={entry.data.title} description={entry.data.description}>
 | 
			
		||||
  {requiresAuth && (
 | 
			
		||||
    <script define:vars={{ requiresAuth, articleTitle: entry.data.title }}>
 | 
			
		||||
      // Client-side authentication check for gated content
 | 
			
		||||
      // Enhanced client-side authentication check for gated content with improved error handling
 | 
			
		||||
      document.addEventListener('DOMContentLoaded', async () => {
 | 
			
		||||
        if (!requiresAuth) return;
 | 
			
		||||
        
 | 
			
		||||
        console.log('[GATED CONTENT] Checking client-side auth for: ' + articleTitle);
 | 
			
		||||
        
 | 
			
		||||
        // Check for auth success indicator in URL (from callback)
 | 
			
		||||
        const urlParams = new URLSearchParams(window.location.search);
 | 
			
		||||
        const authSuccess = urlParams.get('auth') === 'success';
 | 
			
		||||
        
 | 
			
		||||
        // Hide content immediately while checking auth
 | 
			
		||||
        const contentArea = document.querySelector('.article-content');
 | 
			
		||||
        const sidebar = document.querySelector('.article-sidebar');
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        if (contentArea) {
 | 
			
		||||
          contentArea.style.display = 'none';
 | 
			
		||||
        }
 | 
			
		||||
        // DON'T hide the sidebar container - just prevent TOC generation
 | 
			
		||||
        //if (sidebar) {
 | 
			
		||||
          //sidebar.innerHTML = ''; // Clear any content instead of hiding
 | 
			
		||||
        //}
 | 
			
		||||
        
 | 
			
		||||
        // If this is a redirect from successful auth, wait a bit for session to be available
 | 
			
		||||
        if (authSuccess) {
 | 
			
		||||
          console.log('[GATED CONTENT] Auth success detected, waiting for session...');
 | 
			
		||||
          await new Promise(resolve => setTimeout(resolve, 1000));
 | 
			
		||||
          
 | 
			
		||||
          // Clean the URL
 | 
			
		||||
          const cleanUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
 | 
			
		||||
          window.history.replaceState({}, document.title, cleanUrl);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
          const response = await fetch('/api/auth/status');
 | 
			
		||||
@ -93,7 +102,7 @@ const currentUrl = Astro.url.href;
 | 
			
		||||
          if (authRequired && !isAuthenticated) {
 | 
			
		||||
            console.log('[GATED CONTENT] Access denied - showing auth required message: ' + articleTitle);
 | 
			
		||||
            
 | 
			
		||||
            // Show authentication required message (no auto-redirect)
 | 
			
		||||
            // Show authentication required message
 | 
			
		||||
            if (contentArea) {
 | 
			
		||||
              const loginUrl = '/api/auth/login?returnTo=' + encodeURIComponent(window.location.href);
 | 
			
		||||
                contentArea.innerHTML = [
 | 
			
		||||
@ -125,7 +134,7 @@ const currentUrl = Astro.url.href;
 | 
			
		||||
            if (contentArea) {
 | 
			
		||||
              contentArea.style.display = 'block';
 | 
			
		||||
            }
 | 
			
		||||
            // Let TOC generate normally for authenticated users
 | 
			
		||||
            // Generate TOC for authenticated users
 | 
			
		||||
            setTimeout(() => {
 | 
			
		||||
              if (typeof generateTOCContent === 'function') {
 | 
			
		||||
                generateTOCContent();
 | 
			
		||||
@ -134,7 +143,7 @@ const currentUrl = Astro.url.href;
 | 
			
		||||
          }
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
          console.error('[GATED CONTENT] Auth check failed:', error);
 | 
			
		||||
          // On error, show auth required message
 | 
			
		||||
          // On error, show auth required message with retry option
 | 
			
		||||
          if (requiresAuth && contentArea) {
 | 
			
		||||
            const loginUrl = '/api/auth/login?returnTo=' + encodeURIComponent(window.location.href);
 | 
			
		||||
            contentArea.innerHTML = [
 | 
			
		||||
@ -402,25 +411,9 @@ const currentUrl = Astro.url.href;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function generateSidebarTOC() {
 | 
			
		||||
    // NEW: Don't generate TOC for gated content that requires auth
 | 
			
		||||
    // Only generate TOC if not gated content OR user is authenticated
 | 
			
		||||
    if (requiresAuth) {
 | 
			
		||||
      fetch('/api/auth/status')
 | 
			
		||||
        .then(response => response.json())
 | 
			
		||||
        .then(authStatus => {
 | 
			
		||||
          const isAuthenticated = authStatus.gatedContentAuthenticated || false;
 | 
			
		||||
          const authRequired = authStatus.gatedContentAuthRequired || false;
 | 
			
		||||
          
 | 
			
		||||
          // Only generate TOC if user is authenticated for gated content
 | 
			
		||||
          if (authRequired && !isAuthenticated) {
 | 
			
		||||
            return; // Don't generate TOC
 | 
			
		||||
          } else {
 | 
			
		||||
            generateTOCContent(); // Generate TOC for authenticated users
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
        .catch(() => {
 | 
			
		||||
          // On error, don't generate TOC for gated content
 | 
			
		||||
          return;
 | 
			
		||||
        });
 | 
			
		||||
      // For gated content, TOC will be generated by the auth check script
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
@ -614,12 +607,13 @@ const currentUrl = Astro.url.href;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // keep your existing DOMContentLoaded; just ensure this is called
 | 
			
		||||
  // Make generateTOCContent available globally for the auth check script
 | 
			
		||||
  window.generateTOCContent = generateTOCContent;
 | 
			
		||||
 | 
			
		||||
  // Initialize everything on page load
 | 
			
		||||
  document.addEventListener('DOMContentLoaded', () => {
 | 
			
		||||
    // existing:
 | 
			
		||||
    calculateReadingTime();
 | 
			
		||||
    generateSidebarTOC();
 | 
			
		||||
    // new/updated:
 | 
			
		||||
    enhanceCodeCopy();
 | 
			
		||||
  });
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user