auth consolidation

This commit is contained in:
2025-09-18 08:32:08 +02:00
parent 901e60c21b
commit b2b240c16a
10 changed files with 16 additions and 205 deletions

View File

@@ -1,6 +1,6 @@
"use client"
import { useAuth } from "@/contexts/AuthContext"
import { useAuth } from "@/components/providers/auth-provider"
import { useState, useEffect } from "react"
import { ProtectedRoute } from "@/components/auth/ProtectedRoute"
import { useToast } from "@/hooks/use-toast"

View File

@@ -2,7 +2,7 @@
import { useState } from "react"
import { useRouter } from "next/navigation"
import { useAuth } from "@/contexts/AuthContext"
import { useAuth } from "@/components/providers/auth-provider"
// Force dynamic rendering for authentication
export const dynamic = 'force-dynamic'

View File

@@ -31,7 +31,7 @@ import { Edit3, RotateCcw, Loader2, Save, AlertTriangle, Plus, Sparkles } from '
import toast from 'react-hot-toast'
import { apiClient } from '@/lib/api-client'
import { config } from '@/lib/config'
import { useAuth } from '@/contexts/AuthContext'
import { useAuth } from '@/components/providers/auth-provider'
interface PromptTemplate {
id: string

View File

@@ -11,7 +11,7 @@ import { Plus, Database, Upload, Search, Trash2, FileText, AlertCircle } from "l
import { CollectionManager } from "@/components/rag/collection-manager"
import { DocumentUpload } from "@/components/rag/document-upload"
import { DocumentBrowser } from "@/components/rag/document-browser"
import { useAuth } from "@/contexts/AuthContext"
import { useAuth } from "@/components/providers/auth-provider"
import { ProtectedRoute } from '@/components/auth/ProtectedRoute'
import { apiClient } from '@/lib/api-client'

View File

@@ -1,6 +1,6 @@
"use client"
import { useAuth } from "@/contexts/AuthContext"
import { useAuth } from "@/components/providers/auth-provider"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { useState } from "react"

View File

@@ -28,7 +28,7 @@ import {
AlertCircle
} from 'lucide-react';
import { usePlugin, type PluginInfo, type AvailablePlugin } from '../../contexts/PluginContext';
import { useAuth } from '../../contexts/AuthContext';
import { useAuth } from '@/components/providers/auth-provider';
import { PluginConfigurationDialog } from './PluginConfigurationDialog';
interface PluginCardProps {

View File

@@ -8,7 +8,8 @@ import { Alert, AlertDescription } from '@/components/ui/alert';
import { Card, CardContent } from '@/components/ui/card';
import { Skeleton } from '@/components/ui/skeleton';
import { AlertCircle, Loader2 } from 'lucide-react';
import { useAuth } from '../../contexts/AuthContext';
import { useAuth } from '@/components/providers/auth-provider';
import { tokenManager } from '@/lib/token-manager';
import { usePlugin, type PluginInfo } from '../../contexts/PluginContext';
import { config } from '../../lib/config';
@@ -48,8 +49,8 @@ const PluginIframe: React.FC<PluginIframeProps> = ({
// Validate origin - should be from our backend
const allowedOrigins = [
window.location.origin,
config.getBackendUrl(),
config.getApiUrl()
config.API_BASE_URL,
config.API_BASE_URL
].filter(Boolean);
if (!allowedOrigins.some(origin => event.origin.startsWith(origin))) {
@@ -161,7 +162,8 @@ export const PluginPageRenderer: React.FC<PluginPageRendererProps> = ({
pagePath,
componentName
}) => {
const { user, token } = useAuth();
const { user } = useAuth();
const token = tokenManager.getAccessToken();
const {
installedPlugins,
getPluginPages,

View File

@@ -9,6 +9,7 @@ interface User {
id: string
username: string
email: string
name?: string
role: string
permissions: string[]
created_at: string
@@ -18,6 +19,7 @@ interface User {
interface AuthContextType {
user: User | null
isLoading: boolean
isAuthenticated: boolean
login: (username: string, password: string) => Promise<void>
logout: () => void
register: (username: string, email: string, password: string) => Promise<void>
@@ -114,6 +116,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const value: AuthContextType = {
user,
isLoading,
isAuthenticated: !!user,
login,
logout,
register,

View File

@@ -1,194 +0,0 @@
"use client"
import { createContext, useContext, useState, useEffect, ReactNode } from "react"
import { useRouter } from "next/navigation"
import { tokenManager } from "@/lib/token-manager"
// Helper function to get API URL with proper protocol
const getApiUrl = () => {
if (typeof window !== 'undefined') {
const protocol = window.location.protocol.slice(0, -1) // Remove ':' from 'https:'
const host = window.location.hostname
return `${protocol}://${host}`
}
return `http://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`
}
interface User {
id: string
email: string
name: string
role: string
}
interface AuthContextType {
user: User | null
isAuthenticated: boolean
login: (email: string, password: string) => Promise<void>
logout: () => void
isLoading: boolean
}
const AuthContext = createContext<AuthContextType | undefined>(undefined)
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null)
const [isLoading, setIsLoading] = useState(true)
const router = useRouter()
// Initialize auth state and listen to token manager events
useEffect(() => {
const initAuth = async () => {
// Check if we have valid tokens
if (tokenManager.isAuthenticated()) {
// Try to get user info
await fetchUserInfo()
}
setIsLoading(false)
}
// Set up event listeners
const handleTokensUpdated = () => {
// Tokens were updated (refreshed), update user if needed
if (!user) {
fetchUserInfo()
}
}
const handleTokensCleared = () => {
// Tokens were cleared, clear user
setUser(null)
}
const handleSessionExpired = (reason: string) => {
console.log('Session expired:', reason)
setUser(null)
// TokenManager and API client will handle redirect
}
const handleLogout = () => {
setUser(null)
router.push('/login')
}
// Register event listeners
tokenManager.on('tokensUpdated', handleTokensUpdated)
tokenManager.on('tokensCleared', handleTokensCleared)
tokenManager.on('sessionExpired', handleSessionExpired)
tokenManager.on('logout', handleLogout)
// Initialize
initAuth()
// Cleanup
return () => {
tokenManager.off('tokensUpdated', handleTokensUpdated)
tokenManager.off('tokensCleared', handleTokensCleared)
tokenManager.off('sessionExpired', handleSessionExpired)
tokenManager.off('logout', handleLogout)
}
}, [])
const fetchUserInfo = async () => {
try {
const token = await tokenManager.getAccessToken()
if (!token) return
const response = await fetch(`${getApiUrl()}/api-internal/v1/auth/me`, {
headers: {
'Authorization': `Bearer ${token}`,
},
})
if (response.ok) {
const userData = await response.json()
const user = {
id: userData.id || userData.sub,
email: userData.email,
name: userData.name || userData.email,
role: userData.role || 'user',
}
setUser(user)
// Store user info for offline access
if (typeof window !== 'undefined') {
localStorage.setItem('user', JSON.stringify(user))
}
} else if (response.status === 401) {
// Token is invalid or expired, clear it
console.log('Token invalid, clearing tokens')
tokenManager.clearTokens()
setUser(null)
}
} catch (error) {
console.error('Failed to fetch user info:', error)
// If there's an error, clear tokens to be safe
tokenManager.clearTokens()
setUser(null)
}
}
const login = async (email: string, password: string) => {
setIsLoading(true)
try {
const response = await fetch(`${getApiUrl()}/api-internal/v1/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.detail || 'Invalid credentials')
}
const data = await response.json()
// Store tokens in TokenManager
tokenManager.setTokens(data.access_token, data.refresh_token)
// Fetch user info
await fetchUserInfo()
// Navigate to dashboard
router.push('/dashboard')
} catch (error) {
console.error('Login error:', error)
throw error
} finally {
setIsLoading(false)
}
}
const logout = () => {
tokenManager.clearTokens()
setUser(null)
router.push('/login')
}
return (
<AuthContext.Provider
value={{
user,
isAuthenticated: tokenManager.isAuthenticated(),
login,
logout,
isLoading
}}
>
{children}
</AuthContext.Provider>
)
}
export function useAuth() {
const context = useContext(AuthContext)
if (!context) {
throw new Error("useAuth must be used within an AuthProvider")
}
return context
}

View File

@@ -4,7 +4,7 @@
* Plugin Context - Manages plugin state and UI integration
*/
import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react';
import { useAuth } from './AuthContext';
import { useAuth } from '@/components/providers/auth-provider';
import { apiClient } from '@/lib/api-client';
export interface PluginInfo {