Add Clerk authentication to API requests
- Update API client to include Bearer token in requests - Add token getter method to reportService for photo uploads - Create ApiInitializer component to set up auth tokens - Use Clerk's getToken() to retrieve session tokens - Fix 401 Unauthorized errors on report submission
This commit is contained in:
25
src/App.tsx
25
src/App.tsx
@@ -1,6 +1,7 @@
|
||||
import { ClerkProvider } from '@clerk/clerk-react';
|
||||
import { ClerkProvider, useAuth } from '@clerk/clerk-react';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { BrowserRouter, Routes, Route } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
// Import Leaflet CSS
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
@@ -24,6 +25,10 @@ import {
|
||||
WhyCleanPage
|
||||
} from './pages';
|
||||
|
||||
// Services
|
||||
import { apiClient } from './services/api';
|
||||
import { reportService } from './services/reportService';
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
@@ -39,11 +44,26 @@ if (!clerkPubKey) {
|
||||
throw new Error('Missing Clerk Publishable Key');
|
||||
}
|
||||
|
||||
// Component to initialize API clients with auth token
|
||||
function ApiInitializer({ children }: { children: React.ReactNode }) {
|
||||
const { getToken } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
// Set up token getter for API clients
|
||||
const tokenGetter = () => getToken();
|
||||
apiClient.setTokenGetter(tokenGetter);
|
||||
reportService.setTokenGetter(tokenGetter);
|
||||
}, [getToken]);
|
||||
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<ClerkProvider publishableKey={clerkPubKey}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<BrowserRouter>
|
||||
<ApiInitializer>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
{/* Public routes */}
|
||||
<Route path="/sign-in/*" element={<SignInPage />} />
|
||||
@@ -134,6 +154,7 @@ function App() {
|
||||
/>
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</ApiInitializer>
|
||||
</QueryClientProvider>
|
||||
</ClerkProvider>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// API service configuration and base client
|
||||
import { useAuth } from '@clerk/clerk-react';
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api';
|
||||
|
||||
@@ -11,21 +12,30 @@ export interface ApiError {
|
||||
|
||||
export class ApiClient {
|
||||
private baseUrl: string;
|
||||
private getToken?: () => Promise<string | null>;
|
||||
|
||||
constructor(baseUrl: string = API_BASE_URL) {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
setTokenGetter(getToken: () => Promise<string | null>) {
|
||||
this.getToken = getToken;
|
||||
}
|
||||
|
||||
private async request<T>(
|
||||
endpoint: string,
|
||||
options: RequestInit = {}
|
||||
): Promise<T> {
|
||||
const url = `${this.baseUrl}${endpoint}`;
|
||||
|
||||
// Get auth token if available
|
||||
const token = this.getToken ? await this.getToken() : null;
|
||||
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -24,6 +24,12 @@ export interface UploadPhotoResponse {
|
||||
}
|
||||
|
||||
class ReportService {
|
||||
private getToken?: () => Promise<string | null>;
|
||||
|
||||
setTokenGetter(getToken: () => Promise<string | null>) {
|
||||
this.getToken = getToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a photo to the server
|
||||
*/
|
||||
@@ -31,8 +37,14 @@ class ReportService {
|
||||
const formData = new FormData();
|
||||
formData.append('photo', file);
|
||||
|
||||
// Get auth token
|
||||
const token = this.getToken ? await this.getToken() : null;
|
||||
|
||||
const response = await fetch(`${import.meta.env.VITE_API_BASE_URL || 'http://localhost:3005/api'}/reports/upload`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user