Skip to main content

Overview

The logout endpoint terminates the current user session by invalidating the access token and refresh token in Supabase Auth. This ensures the user is fully logged out and cannot access protected resources without re-authenticating.
Logout clears the session server-side. Make sure to also clear any client-side session data (cookies, localStorage) after calling this endpoint.

Endpoint

POST /api/auth/logout

Authentication

Authorization
string
required
Bearer token obtained from login.Format: Bearer {access_token}

Request

This endpoint does not require a request body. The user session is identified by the access token in the Authorization header.

Response

success
boolean
Always true when logout is successful.
message
string
Confirmation message.

Request Example

cURL
curl -X POST https://jcv24fitness.com/api/auth/logout \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
JavaScript
const response = await fetch('https://jcv24fitness.com/api/auth/logout', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
  }
});

const data = await response.json();
TypeScript with Fetch
const logout = async (accessToken: string) => {
  const response = await fetch('https://jcv24fitness.com/api/auth/logout', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
    },
  });
  
  if (!response.ok) {
    throw new Error('Logout failed');
  }
  
  return response.json();
};

Response Example

{
  "success": true,
  "message": "Successfully logged out"
}

Error Codes

CodeDescription
UNAUTHORIZEDAccess token is invalid, expired, or missing
LOGOUT_ERRORServer-side error during logout process
SUPABASE_ERRORInternal error from Supabase Auth service

Implementation Details

Logout Flow

  1. Client sends POST request with Authorization header containing access token
  2. Supabase Auth validates the token
  3. If valid, Supabase invalidates both access token and refresh token
  4. Server responds with success confirmation
  5. Client clears local session data (cookies, localStorage, context state)
  6. Client redirects user to login page or home page

Token Invalidation

When logout is called:
  • The current access token is immediately invalidated
  • The associated refresh token is revoked and cannot be used to get new access tokens
  • Any subsequent API requests with the old token will return 401 Unauthorized
  • The session is removed from Supabase’s session store

Client-Side Cleanup

After a successful logout, the client should:
  1. Remove access token from storage
  2. Remove refresh token from storage
  3. Clear user context/state
  4. Clear any cached user data
  5. Redirect to public page

Frontend Integration

Using the Auth Hook

import { useAuth } from '@/features/auth';
import { useRouter } from 'next/navigation';

function LogoutButton() {
  const { signOut } = useAuth();
  const router = useRouter();
  
  const handleLogout = async () => {
    await signOut();
    
    // User is now logged out
    // Redirect to home page
    router.push('/');
  };
  
  return (
    <button onClick={handleLogout}>
      Cerrar sesión
    </button>
  );
}

Complete Logout Component

import { useAuth } from '@/features/auth';
import { useRouter } from 'next/navigation';
import { useState } from 'react';

function LogoutButton() {
  const { signOut, user } = useAuth();
  const router = useRouter();
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  
  const handleLogout = async () => {
    if (!user) return;
    
    setIsLoading(true);
    setError(null);
    
    try {
      await signOut();
      
      // Optional: Clear additional local data
      localStorage.removeItem('wizard_data');
      
      // Redirect to home
      router.push('/');
    } catch (err) {
      setError('Failed to logout. Please try again.');
      console.error('Logout error:', err);
    } finally {
      setIsLoading(false);
    }
  };
  
  return (
    <div>
      <button 
        onClick={handleLogout}
        disabled={isLoading}
        className="btn-logout"
      >
        {isLoading ? 'Cerrando sesión...' : 'Cerrar sesión'}
      </button>
      
      {error && (
        <p className="text-red-500 text-sm mt-2">{error}</p>
      )}
    </div>
  );
}

Auth Context Implementation

The signOut function in the Auth context:
const signOut = async () => {
  const supabase = createClient();
  if (!supabase) return;
  
  // Call Supabase signOut
  await supabase.auth.signOut();
  
  // Context automatically updates state via onAuthStateChange listener
  // No need to manually clear state here
};
The AuthProvider automatically listens to Supabase auth state changes, so when signOut() is called, the context state (user, session) is automatically cleared.

Session Cleanup

Automatic Cleanup

The AuthProvider handles automatic cleanup:
supabase.auth.onAuthStateChange((event, session) => {
  if (event === 'SIGNED_OUT') {
    setState({
      user: null,
      session: null,
      profile: null,
      isLoading: false,
      isAuthenticated: false,
    });
  }
});

Manual Cleanup (Optional)

For additional cleanup:
const handleLogout = async () => {
  await signOut();
  
  // Clear wizard data
  localStorage.removeItem('wizard_data');
  
  // Clear payment data
  localStorage.removeItem('payment_info');
  
  // Clear any cached API responses
  queryClient.clear();
  
  // Redirect
  router.push('/login');
};

Security Considerations

Always logout users when they close sensitive pages or after a period of inactivity.

Best Practices

  1. Use secure token storage: Store tokens in httpOnly cookies when possible
  2. Clear all session data: Remove tokens, user data, and cached content
  3. Invalidate server-side: Always call the logout endpoint, don’t just clear client storage
  4. Redirect immediately: Don’t leave users on protected pages after logout
  5. Handle errors gracefully: Show user-friendly messages if logout fails

Automatic Logout Scenarios

  • Token expiration (1 hour for access tokens)
  • Session timeout after inactivity
  • User changes password (invalidates all sessions)
  • User initiates logout from another device (if implementing multi-device session management)

Multi-Tab Behavior

Supabase Auth automatically synchronizes session state across browser tabs:
  • If a user logs out in one tab, all other tabs are automatically updated
  • The onAuthStateChange listener fires in all tabs when logout occurs
  • No manual synchronization needed
// This happens automatically in all tabs
supabase.auth.onAuthStateChange((event) => {
  if (event === 'SIGNED_OUT') {
    // Update UI in this tab
    router.push('/login');
  }
});

Testing

Test Logout Success

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { AuthProvider } from '@/features/auth';
import LogoutButton from './LogoutButton';

test('should logout user successfully', async () => {
  render(
    <AuthProvider>
      <LogoutButton />
    </AuthProvider>
  );
  
  const button = screen.getByText('Cerrar sesión');
  fireEvent.click(button);
  
  await waitFor(() => {
    expect(screen.queryByText('Dashboard')).not.toBeInTheDocument();
  });
});

Test Error Handling

test('should handle logout error', async () => {
  // Mock supabase.auth.signOut to fail
  const mockSignOut = jest.fn().mockRejectedValue(new Error('Network error'));
  
  render(<LogoutButton />);
  
  const button = screen.getByText('Cerrar sesión');
  fireEvent.click(button);
  
  await waitFor(() => {
    expect(screen.getByText(/Failed to logout/i)).toBeInTheDocument();
  });
});

Build docs developers (and LLMs) love