From 60b75669fabac52205569920c8566f999130463c Mon Sep 17 00:00:00 2001 From: nick134 Date: Wed, 21 Jan 2026 12:43:07 +0100 Subject: [PATCH 1/2] chore: make envs optional for standalone usage with akashml api key --- app/api/auth/[...auth0]/route.ts | 27 +- app/api/auth/session/refresh/route.ts | 17 +- app/api/auth/session/route.ts | 48 +- app/api/auth/status/route.ts | 9 +- app/api/chat/route.ts | 7 +- app/api/chats/load/route.ts | 8 +- app/api/models/all/route.ts | 76 +- app/api/models/route.ts | 6 +- app/api/rate-limit/status/route.ts | 8 +- app/api/user/account/route.ts | 8 +- app/api/user/chat-history/route.ts | 8 +- app/api/user/initialize/route.ts | 33 +- app/api/user/verification-status/route.ts | 16 +- app/config/api.ts | 3 +- app/context/ChatContext.tsx | 58 +- components/auth/user-menu.tsx | 9 +- components/chat/rate-limit-message.tsx | 8 +- hooks/use-auth-status.ts | 33 + lib/auth.ts | 65 +- lib/auth0-management.ts | 27 +- lib/middleware/auth.ts | 12 +- lib/models.ts | 150 +-- lib/postgres.ts | 55 +- lib/rate-limit.ts | 74 +- lib/redis.ts | 27 +- lib/services/litellm-service.ts | 54 +- lib/utils.ts | 46 +- package-lock.json | 1070 ++++++++++----------- 28 files changed, 1092 insertions(+), 870 deletions(-) create mode 100644 hooks/use-auth-status.ts diff --git a/app/api/auth/[...auth0]/route.ts b/app/api/auth/[...auth0]/route.ts index dff6913..e67e8ce 100644 --- a/app/api/auth/[...auth0]/route.ts +++ b/app/api/auth/[...auth0]/route.ts @@ -1,3 +1,4 @@ +import { isAuth0Configured, isDevBypassEnabled } from '@/lib/auth'; import { handleAuth } from '@auth0/nextjs-auth0'; import { NextRequest, NextResponse } from 'next/server'; @@ -26,10 +27,6 @@ function getDevUser() { }; } -function isDevBypassEnabled() { - return process.env.NODE_ENV === 'development' && process.env.DEV_BYPASS_AUTH === 'true'; -} - function handleDevLogin(request: NextRequest): NextResponse { const returnTo = request.nextUrl.searchParams.get('returnTo') || '/'; const redirectUrl = new URL(returnTo, request.url); @@ -77,16 +74,36 @@ export async function GET(request: NextRequest, context: { params: Promise<{ aut const params = await context.params; const route = params.auth0?.[0]; - if (isDevBypassEnabled()) { + // Handle dev bypass or when Auth0 is not configured + if (isDevBypassEnabled() || !isAuth0Configured()) { switch (route) { case 'login': + if (!isAuth0Configured()) { + return NextResponse.json({ error: 'Authentication not configured' }, { status: 501 }); + } return handleDevLogin(request); case 'logout': + if (!isAuth0Configured()) { + return NextResponse.redirect(new URL('/', request.url)); + } return handleDevLogout(request); case 'me': + if (!isAuth0Configured()) { + return NextResponse.json(null, { status: 401 }); + } return handleDevMe(request); case 'callback': return NextResponse.redirect(new URL('/', request.url)); + case 'session': + case 'status': + if (!isAuth0Configured()) { + return NextResponse.json({ isAuthenticated: false }); + } + break; + default: + if (!isAuth0Configured()) { + return NextResponse.json({ error: 'Authentication not configured' }, { status: 501 }); + } } } diff --git a/app/api/auth/session/refresh/route.ts b/app/api/auth/session/refresh/route.ts index 7dcde9e..f15dddd 100644 --- a/app/api/auth/session/refresh/route.ts +++ b/app/api/auth/session/refresh/route.ts @@ -3,24 +3,21 @@ import crypto from 'crypto'; import { NextResponse } from 'next/server'; import { CACHE_TTL } from '@/app/config/api'; -import { checkApiAccessToken } from '@/lib/auth'; -import { validateSession, storeSession } from '@/lib/redis'; -import redis from '@/lib/redis'; +import redis, { validateSession, storeSession, isRedisAvailable } from '@/lib/redis'; const RATE_LIMIT_WINDOW = Math.floor(CACHE_TTL * 0.20 * 0.25); const MAX_REQUESTS = 3; async function isRateLimited(token: string): Promise { + if (!redis) {return false;} + const key = `ratelimit:refresh:${token}`; const now = Math.floor(Date.now() / 1000); try { await redis.zadd(key, now, now.toString()); - await redis.zremrangebyscore(key, 0, now - RATE_LIMIT_WINDOW); - const requestCount = await redis.zcard(key); - await redis.expire(key, RATE_LIMIT_WINDOW); return requestCount > MAX_REQUESTS; @@ -53,9 +50,9 @@ export async function POST(request: Request) { return NextResponse.json({ error: 'No session token found' }, { status: 401 }); } - const authCheckResponse = checkApiAccessToken(request); - if (authCheckResponse) { - return authCheckResponse; + // Skip session management if Redis is not available + if (!isRedisAvailable()) { + return NextResponse.json({ success: true }); } if (await isRateLimited(currentToken)) { @@ -64,7 +61,7 @@ export async function POST(request: Request) { { status: 429 } ); } - const ttl = await redis.ttl(`session:${currentToken}`); + const ttl = await redis!.ttl(`session:${currentToken}`); const isValid = await validateSession(currentToken); if (isValid && ttl > CACHE_TTL * 0.20) { diff --git a/app/api/auth/session/route.ts b/app/api/auth/session/route.ts index dc7deda..06b1fa6 100644 --- a/app/api/auth/session/route.ts +++ b/app/api/auth/session/route.ts @@ -4,7 +4,7 @@ import { NextResponse } from 'next/server'; import { CACHE_TTL } from '@/app/config/api'; import { checkApiAccessToken } from '@/lib/auth'; -import { storeSession } from '@/lib/redis'; +import { storeSession, validateSession, isRedisAvailable } from '@/lib/redis'; export async function GET(request: Request) { if (process.env.NODE_ENV === 'production') { @@ -27,12 +27,56 @@ export async function GET(request: Request) { return NextResponse.json({ error: 'Invalid request - invalid fetch mode' }, { status: 403 }); } } - + + // If Redis is not available, use a simple cookie flag instead + if (!isRedisAvailable()) { + const cookieHeader = request.headers.get('cookie'); + const hasAuthCookie = cookieHeader?.includes('session_token=validated'); + + // If already validated (has cookie), allow through + if (hasAuthCookie) { + return NextResponse.json({ success: true }); + } + + // No cookie, require access token + const authCheckResponse = checkApiAccessToken(request); + if (authCheckResponse) { + return authCheckResponse; + } + + // Access token valid, set persistent cookie + const response = NextResponse.json({ success: true }); + response.cookies.set('session_token', 'validated', { + httpOnly: process.env.NODE_ENV === 'production', + secure: process.env.NODE_ENV === 'production', + sameSite: 'strict', + maxAge: 24 * 60 * 60, + path: '/', + partitioned: process.env.NODE_ENV === 'production', + }); + return response; + } + + // Check if there's already a valid session cookie + const cookieHeader = request.headers.get('cookie'); + const existingToken = cookieHeader?.split(';') + .find(c => c.trim().startsWith('session_token=')) + ?.split('=')[1]; + + if (existingToken) { + const isValid = await validateSession(existingToken); + if (isValid) { + return NextResponse.json({ success: true }); + } + } + + // No valid session, require access token const authCheckResponse = checkApiAccessToken(request); if (authCheckResponse) { return authCheckResponse; } + // Create new session const sessionToken = crypto.randomBytes(32).toString('hex'); await storeSession(sessionToken); diff --git a/app/api/auth/status/route.ts b/app/api/auth/status/route.ts index 1855034..a017050 100644 --- a/app/api/auth/status/route.ts +++ b/app/api/auth/status/route.ts @@ -1,16 +1,17 @@ import { NextResponse } from 'next/server'; import { ACCESS_TOKEN } from '@/app/config/api'; +import { isAuth0Configured } from '@/lib/auth'; /** - * API endpoint to check if an access token is required for the application - * This allows the client to proactively check if token authentication is needed + * API endpoint to check auth configuration status */ export async function GET() { return NextResponse.json({ requiresAccessToken: !!ACCESS_TOKEN, - message: ACCESS_TOKEN - ? 'This application requires an access token to continue' + authEnabled: isAuth0Configured(), + message: ACCESS_TOKEN + ? 'This application requires an access token to continue' : 'No access token required for this application', }); } \ No newline at end of file diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index f325982..19626c6 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -1,13 +1,12 @@ import { createOpenAI } from '@ai-sdk/openai'; -import { getSession } from '@auth0/nextjs-auth0'; import { streamText, createDataStreamResponse, generateText, simulateReadableStream, Message } from 'ai'; -import { NextRequest, NextResponse } from 'next/server'; +import { NextRequest } from 'next/server'; import cl100k_base from "tiktoken/encoders/cl100k_base.json"; import { Tiktoken } from "tiktoken/lite"; import { apiEndpoint, apiKey, imgGenFnModel, DEFAULT_SYSTEM_PROMPT } from '@/app/config/api'; import { defaultModel } from '@/app/config/models'; -import { withSessionAuth } from '@/lib/auth'; +import { withSessionAuth, getOptionalSession } from '@/lib/auth'; import { getAvailableModelsForUser } from '@/lib/models'; import { checkTokenLimit, incrementTokenUsageWithMultiplier, getClientIP, getRateLimitConfigForUser, storeConversationTokens } from '@/lib/rate-limit'; import { LiteLLMService } from '@/lib/services/litellm-service'; @@ -103,7 +102,7 @@ function createOpenAIWithRateLimit(apiKey: string) { const openai = createOpenAIWithRateLimit(apiKey); async function handlePostRequest(req: NextRequest) { - const session = await getSession(req, NextResponse.next()); + const session = await getOptionalSession(req); const isAuthenticated = !!session?.user; let userApiKey: string | null = null; diff --git a/app/api/chats/load/route.ts b/app/api/chats/load/route.ts index 4ef7fa2..eed06e5 100644 --- a/app/api/chats/load/route.ts +++ b/app/api/chats/load/route.ts @@ -1,12 +1,16 @@ -import { getSession } from '@auth0/nextjs-auth0'; import { NextRequest, NextResponse } from 'next/server'; +import { getOptionalSession, isAuth0Configured } from '@/lib/auth'; import { createDatabaseService } from '@/lib/services/database-service'; import { createEncryptionService } from '@/lib/services/encryption-service'; export async function GET(request: NextRequest) { try { - const session = await getSession(request, new NextResponse()); + if (!isAuth0Configured()) { + return NextResponse.json({ chatSessions: [], count: 0 }); + } + + const session = await getOptionalSession(request); if (!session?.user?.sub) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } diff --git a/app/api/models/all/route.ts b/app/api/models/all/route.ts index 8c47eea..8d57064 100644 --- a/app/api/models/all/route.ts +++ b/app/api/models/all/route.ts @@ -1,8 +1,9 @@ -import { getSession } from '@auth0/nextjs-auth0'; import { NextRequest, NextResponse } from 'next/server'; import { apiEndpoint, apiKey } from '@/app/config/api'; +import { getOptionalSession } from '@/lib/auth'; import { getUserTier, getAllModels } from '@/lib/database'; +import { isDatabaseAvailable } from '@/lib/postgres'; // Models that are always available regardless of LiteLLM API status const ALWAYS_AVAILABLE_MODELS = ['AkashGen']; @@ -40,22 +41,11 @@ interface ModelWithAccess { export async function GET(req: NextRequest) { try { - // Check if user is authenticated - const session = await getSession(req, NextResponse.next()); + // Check if user is authenticated (optional - works without Auth0) + const session = await getOptionalSession(req); const userId = session?.user?.sub || null; - - // Get user's tier - let userTier = null; - if (userId) { - userTier = await getUserTier(userId); - } - - const userTierName = userTier?.name || 'permissionless'; - - // Get all models from database (across all tiers) - const allModels = await getAllModels(); - - // Check which models are currently available via LiteLLM API + + // Check which models are currently available via API let apiModels: any[] = []; try { const response = await fetch(apiEndpoint + '/models', { @@ -66,10 +56,58 @@ export async function GET(req: NextRequest) { const apiData = await response.json(); apiModels = apiData.data || []; } catch (error) { - console.warn('[API] Failed to fetch from LiteLLM API:', error); - // Continue with empty array - models will be marked as unavailable + console.warn('[API] Failed to fetch from API:', error); } - + + // If database is not available, return models directly from API + if (!isDatabaseAvailable()) { + const modelsFromApi = apiModels.map((apiModel: any) => ({ + id: apiModel.id, + model_id: apiModel.id, + api_id: apiModel.id, + name: apiModel.id.split('/').pop() || apiModel.id, + description: `${apiModel.id} model`, + tier_requirement: 'permissionless', + available: true, + temperature: 0.7, + top_p: 0.95, + token_limit: 128000, + owned_by: apiModel.owned_by, + display_order: 0, + user_has_access: true, + is_available_now: true, + action_button: 'start_chat' as const, + action_text: 'Start Chat' + })); + + return NextResponse.json({ + models: modelsFromApi, + user_tier: 'permissionless', + stats: { + total_models: modelsFromApi.length, + available_now: modelsFromApi.length, + user_accessible: modelsFromApi.length, + user_available: modelsFromApi.length, + by_tier: { + permissionless: modelsFromApi.length, + extended: 0, + pro: 0 + } + } + }); + } + + // Get user's tier + let userTier = null; + if (userId) { + userTier = await getUserTier(userId); + } + + const userTierName = userTier?.name || 'permissionless'; + + // Get all models from database (across all tiers) + const allModels = await getAllModels(); + // Create set of available API model IDs for quick lookup const availableApiIds = new Set(apiModels.map(model => model.id)); diff --git a/app/api/models/route.ts b/app/api/models/route.ts index 037619d..504abd4 100644 --- a/app/api/models/route.ts +++ b/app/api/models/route.ts @@ -1,12 +1,12 @@ -import { getSession } from '@auth0/nextjs-auth0'; import { NextRequest, NextResponse } from 'next/server'; +import { getOptionalSession } from '@/lib/auth'; import { getAvailableModelsForUser } from '@/lib/models'; export async function GET(req: NextRequest) { try { - // Check if user is authenticated - const session = await getSession(req, NextResponse.next()); + // Check if user is authenticated (optional - works without Auth0) + const session = await getOptionalSession(req); const userId = session?.user?.sub || null; // Get models based on user's tier (or anonymous/permissionless for non-logged-in users) diff --git a/app/api/rate-limit/status/route.ts b/app/api/rate-limit/status/route.ts index c56d767..7a51fdd 100644 --- a/app/api/rate-limit/status/route.ts +++ b/app/api/rate-limit/status/route.ts @@ -1,6 +1,6 @@ -import { getSession } from '@auth0/nextjs-auth0'; -import { NextRequest, NextResponse } from 'next/server'; +import { NextRequest } from 'next/server'; +import { getOptionalSession } from '@/lib/auth'; import { checkTokenLimit, getClientIP, getRateLimitConfigForUser, getConversationTokens } from '@/lib/rate-limit'; export async function GET(req: NextRequest) { @@ -21,8 +21,8 @@ export async function GET(req: NextRequest) { }); } - // Check authentication status - const session = await getSession(req, NextResponse.next()); + // Check authentication status (optional - works without Auth0) + const session = await getOptionalSession(req); const isAuthenticated = !!session?.user; // Determine rate limit identifier and config diff --git a/app/api/user/account/route.ts b/app/api/user/account/route.ts index cb48915..ec23f4a 100644 --- a/app/api/user/account/route.ts +++ b/app/api/user/account/route.ts @@ -1,11 +1,15 @@ -import { getSession } from '@auth0/nextjs-auth0'; import { NextRequest, NextResponse } from 'next/server'; +import { getOptionalSession, isAuth0Configured } from '@/lib/auth'; import { deleteAllUserData } from '@/lib/database'; export async function DELETE(req: NextRequest) { try { - const session = await getSession(req, NextResponse.next()); + if (!isAuth0Configured()) { + return NextResponse.json({ error: 'Authentication not configured' }, { status: 401 }); + } + + const session = await getOptionalSession(req); if (!session?.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } diff --git a/app/api/user/chat-history/route.ts b/app/api/user/chat-history/route.ts index 60b58f1..8d77ec5 100644 --- a/app/api/user/chat-history/route.ts +++ b/app/api/user/chat-history/route.ts @@ -1,11 +1,15 @@ -import { getSession } from '@auth0/nextjs-auth0'; import { NextRequest, NextResponse } from 'next/server'; +import { getOptionalSession, isAuth0Configured } from '@/lib/auth'; import { deleteAllUserChatHistory } from '@/lib/database'; export async function DELETE(req: NextRequest) { try { - const session = await getSession(req, NextResponse.next()); + if (!isAuth0Configured()) { + return NextResponse.json({ error: 'Authentication not configured' }, { status: 401 }); + } + + const session = await getOptionalSession(req); if (!session?.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } diff --git a/app/api/user/initialize/route.ts b/app/api/user/initialize/route.ts index cb485be..4ebd441 100644 --- a/app/api/user/initialize/route.ts +++ b/app/api/user/initialize/route.ts @@ -1,37 +1,20 @@ -import { getSession } from '@auth0/nextjs-auth0'; import { NextRequest, NextResponse } from 'next/server'; +import { getOptionalSession, isAuth0Configured, isDevBypassEnabled } from '@/lib/auth'; import { getUserPreferences, upsertUserPreferences, updateUserTier } from '@/lib/database'; import { LiteLLMService } from '@/lib/services/litellm-service'; -function isDevBypassEnabled() { - return process.env.NODE_ENV === 'development' && process.env.DEV_BYPASS_AUTH === 'true'; -} - export async function POST(req: NextRequest) { try { - if (isDevBypassEnabled()) { - const devUserId = process.env.DEV_USER_ID || 'dev-test-user'; - try { - const existingPreferences = await getUserPreferences(devUserId); - return NextResponse.json({ - success: true, - isNewUser: !existingPreferences, - message: existingPreferences - ? 'User initialized successfully' - : 'New user created and initialized with extended tier' - }); - } catch (error) { - console.log('[DEV MODE] User initialize - DB error (ignored):', error); - return NextResponse.json({ - success: true, - isNewUser: false, - message: 'User initialized successfully (dev mode)' - }); - } + if (isDevBypassEnabled() || !isAuth0Configured()) { + return NextResponse.json({ + success: true, + isNewUser: false, + message: 'User initialized successfully (no auth mode)' + }); } - const session = await getSession(req, NextResponse.next()); + const session = await getOptionalSession(req); if (!session?.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } diff --git a/app/api/user/verification-status/route.ts b/app/api/user/verification-status/route.ts index 8ed0a9d..43402a4 100644 --- a/app/api/user/verification-status/route.ts +++ b/app/api/user/verification-status/route.ts @@ -1,12 +1,8 @@ -import { getSession } from '@auth0/nextjs-auth0'; import { NextRequest, NextResponse } from 'next/server'; +import { getOptionalSession, isAuth0Configured, isDevBypassEnabled } from '@/lib/auth'; import { auth0Management } from '@/lib/auth0-management'; -function isDevBypassEnabled() { - return process.env.NODE_ENV === 'development' && process.env.DEV_BYPASS_AUTH === 'true'; -} - function getDevVerificationStatus() { return NextResponse.json({ emailVerified: true, @@ -28,11 +24,11 @@ function getDevVerificationStatus() { export async function GET(req: NextRequest) { try { - if (isDevBypassEnabled()) { + if (isDevBypassEnabled() || !isAuth0Configured()) { return getDevVerificationStatus(); } - const session = await getSession(req, NextResponse.next()); + const session = await getOptionalSession(req); if (!session?.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } @@ -78,8 +74,8 @@ export async function GET(req: NextRequest) { export async function POST(req: NextRequest) { try { - if (isDevBypassEnabled()) { - return NextResponse.json({ + if (isDevBypassEnabled() || !isAuth0Configured()) { + return NextResponse.json({ success: true, emailVerified: true, marketingConsent: true, @@ -87,7 +83,7 @@ export async function POST(req: NextRequest) { }); } - const session = await getSession(req, NextResponse.next()); + const session = await getOptionalSession(req); if (!session?.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } diff --git a/app/config/api.ts b/app/config/api.ts index 3b5e226..d4bed56 100644 --- a/app/config/api.ts +++ b/app/config/api.ts @@ -1,9 +1,10 @@ -export const apiEndpoint = process.env.API_ENDPOINT || 'https://chatapi.akash.network/api/v1'; +export const apiEndpoint = process.env.API_ENDPOINT || 'https://api.akashml.com/v1'; export const apiKey = process.env.API_KEY; export const imgApiKey = process.env.IMG_API_KEY; export const imgEndpoint = process.env.IMG_ENDPOINT export const imgGenFnModel = process.env.IMG_GEN_FN_MODEL export const CACHE_TTL = Number(process.env.CACHE_TTL) || 10 * 60; // 10 minutes +export const SESSION_TTL = Number(process.env.SESSION_TTL) || 24 * 60 * 60; // 24 hours export const ACCESS_TOKEN = process.env.ACCESS_TOKEN || null; export const DEFAULT_SYSTEM_PROMPT = `You are a skilled conversationalist who adapts naturally to what users need. Your responses match the situation—whether someone wants deep analysis, casual chat, emotional support, creative collaboration, or just needs to vent. Core Approach diff --git a/app/context/ChatContext.tsx b/app/context/ChatContext.tsx index 57ddb13..3d4473a 100644 --- a/app/context/ChatContext.tsx +++ b/app/context/ChatContext.tsx @@ -16,7 +16,7 @@ import { useEncryptedSettings, UserPreferences } from '@/hooks/use-encrypted-set import { Folder, useFolders } from '@/hooks/use-folders'; import { useRateLimit } from '@/hooks/use-rate-limit'; import { safeSetItem } from '@/lib/local-storage-manager'; -import { getAccessToken, storeAccessToken, processMessages } from '@/lib/utils'; +import { validateAccessToken, processMessages } from '@/lib/utils'; const SELECTED_MODEL_KEY = 'selectedModel'; const CURRENT_SYSTEM_PROMPT_KEY = 'currentSystemPrompt'; @@ -530,32 +530,32 @@ export const ChatProvider: React.FC<{ children: React.ReactNode }> = ({ children if (statusResponse.ok) { const { requiresAccessToken } = await statusResponse.json(); - // If an access token is required but not present, show the dialog - if (requiresAccessToken && !getAccessToken()) { - setIsAccessError(true); - setSessionInitialized(true); - return; + // If an access token is required, try to establish session + // If it fails (no valid session cookie), show the access token dialog + if (requiresAccessToken) { + const response = await fetch('/api/auth/session/'); + if (!response.ok) { + const data = await response.json(); + if (response.status === 403 && data.error === 'Access token required') { + setIsAccessError(true); + setSessionInitialized(true); + return; + } + } } } - const accessToken = getAccessToken(); - const response = await fetch('/api/auth/session/', accessToken ? { - headers: { - 'Authorization': `Bearer ${accessToken}` - } - } : {}); + // Try to establish session (works with or without access token requirement) + const response = await fetch('/api/auth/session/'); if (!response.ok) { const data = await response.json(); - if (response.status === 403 && data.error === 'Invalid Access token' ) { + if (response.status === 403 && (data.error === 'Access token required' || data.error === 'Invalid Access token')) { setIsAccessError(true); } else { throw new Error('Failed to initialize session'); } } setSessionInitialized(true); - - // Check and cleanup local storage if needed - // Storage cleanup is now handled by safeSetItem when errors occur } catch (error) { setSessionError('Unable to establish a secure session. Please try refreshing the page.'); } @@ -696,29 +696,17 @@ export const ChatProvider: React.FC<{ children: React.ReactNode }> = ({ children const handleAccessTokenSubmit = async () => { if (accessTokenInput.trim()) { try { - await storeAccessToken(accessTokenInput.trim()); + const isValid = await validateAccessToken(accessTokenInput.trim()); - // Try to validate the token with the server - const response = await fetch('/api/auth/session/', { - headers: { - 'Authorization': `Bearer ${getAccessToken()}` - } - }); - - if (!response.ok) { - const data = await response.json(); - if (response.status === 403 && data.error === 'Invalid Access token') { - setModelError('Access token is invalid. Please check and try again.'); - return; - } else { - throw new Error('Failed to validate access token'); - } + if (!isValid) { + setModelError('Access token is invalid. Please check and try again.'); + return; } - - // Token is valid + + // Token is valid and session created setIsAccessError(false); setModelError(null); - + setAccessTokenInput(''); setSessionInitialized(true); } catch (error) { setModelError('Failed to validate access token. Please try again.'); diff --git a/components/auth/user-menu.tsx b/components/auth/user-menu.tsx index 238aad3..95400da 100644 --- a/components/auth/user-menu.tsx +++ b/components/auth/user-menu.tsx @@ -12,6 +12,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; +import { useAuthStatus } from '@/hooks/use-auth-status'; import { cleanupUserDataOnLogout } from '@/lib/data-sync'; import { cn } from '@/lib/utils'; @@ -22,6 +23,7 @@ interface UserMenuProps { export function UserMenu({ className }: UserMenuProps) { const { user, isLoading } = useUser(); const { resetAllState } = useChatContext(); + const { authEnabled, isLoading: authLoading } = useAuthStatus(); const handleLogout = () => { @@ -39,13 +41,18 @@ export function UserMenu({ className }: UserMenuProps) { } }; - if (isLoading) { + if (isLoading || authLoading) { return (
); } + // Don't show sign in button if auth is not configured if (!user) { + if (!authEnabled) { + return null; + } + return (