mirror of
https://github.com/aljazceru/enclava.git
synced 2025-12-17 07:24:34 +01:00
tshoot
This commit is contained in:
@@ -182,6 +182,9 @@ async def login(
|
|||||||
|
|
||||||
# Create tokens
|
# Create tokens
|
||||||
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||||
|
logger.info(f"Creating access token with expiration: {access_token_expires}")
|
||||||
|
logger.info(f"ACCESS_TOKEN_EXPIRE_MINUTES from settings: {settings.ACCESS_TOKEN_EXPIRE_MINUTES}")
|
||||||
|
|
||||||
access_token = create_access_token(
|
access_token = create_access_token(
|
||||||
data={
|
data={
|
||||||
"sub": str(user.id),
|
"sub": str(user.id),
|
||||||
@@ -234,6 +237,10 @@ async def refresh_token(
|
|||||||
|
|
||||||
# Create new access token
|
# Create new access token
|
||||||
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||||
|
logger.info(f"REFRESH: Creating new access token with expiration: {access_token_expires}")
|
||||||
|
logger.info(f"REFRESH: ACCESS_TOKEN_EXPIRE_MINUTES from settings: {settings.ACCESS_TOKEN_EXPIRE_MINUTES}")
|
||||||
|
logger.info(f"REFRESH: Current UTC time: {datetime.utcnow().isoformat()}")
|
||||||
|
|
||||||
access_token = create_access_token(
|
access_token = create_access_token(
|
||||||
data={
|
data={
|
||||||
"sub": str(user.id),
|
"sub": str(user.id),
|
||||||
|
|||||||
@@ -22,22 +22,22 @@ class Settings(BaseSettings):
|
|||||||
LOG_LLM_PROMPTS: bool = os.getenv("LOG_LLM_PROMPTS", "False").lower() == "true" # Set to True to log prompts and context sent to LLM
|
LOG_LLM_PROMPTS: bool = os.getenv("LOG_LLM_PROMPTS", "False").lower() == "true" # Set to True to log prompts and context sent to LLM
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
DATABASE_URL: str = os.getenv("DATABASE_URL", "postgresql://empire_user:empire_pass@localhost:5432/empire_db")
|
DATABASE_URL: str = os.getenv("DATABASE_URL")
|
||||||
|
|
||||||
# Redis
|
# Redis
|
||||||
REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379")
|
REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379")
|
||||||
|
|
||||||
# Security
|
# Security
|
||||||
JWT_SECRET: str = os.getenv("JWT_SECRET", "your-super-secret-jwt-key-here")
|
JWT_SECRET: str = os.getenv("JWT_SECRET")
|
||||||
JWT_ALGORITHM: str = os.getenv("JWT_ALGORITHM", "HS256")
|
JWT_ALGORITHM: str = os.getenv("JWT_ALGORITHM", "HS256")
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
|
ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "1440")) # 24 hours
|
||||||
REFRESH_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("REFRESH_TOKEN_EXPIRE_MINUTES", "10080")) # 7 days
|
REFRESH_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("REFRESH_TOKEN_EXPIRE_MINUTES", "10080")) # 7 days
|
||||||
SESSION_EXPIRE_MINUTES: int = int(os.getenv("SESSION_EXPIRE_MINUTES", "1440")) # 24 hours
|
SESSION_EXPIRE_MINUTES: int = int(os.getenv("SESSION_EXPIRE_MINUTES", "1440")) # 24 hours
|
||||||
API_KEY_PREFIX: str = os.getenv("API_KEY_PREFIX", "en_")
|
API_KEY_PREFIX: str = os.getenv("API_KEY_PREFIX", "en_")
|
||||||
|
|
||||||
# Admin user provisioning (used only on first startup)
|
# Admin user provisioning (used only on first startup)
|
||||||
ADMIN_EMAIL: str = os.getenv("ADMIN_EMAIL", "admin@example.com")
|
ADMIN_EMAIL: str = os.getenv("ADMIN_EMAIL")
|
||||||
ADMIN_PASSWORD: str = os.getenv("ADMIN_PASSWORD", "admin123")
|
ADMIN_PASSWORD: str = os.getenv("ADMIN_PASSWORD")
|
||||||
|
|
||||||
# Base URL for deriving CORS origins
|
# Base URL for deriving CORS origins
|
||||||
BASE_URL: str = os.getenv("BASE_URL", "localhost")
|
BASE_URL: str = os.getenv("BASE_URL", "localhost")
|
||||||
@@ -142,3 +142,11 @@ class Settings(BaseSettings):
|
|||||||
|
|
||||||
# Global settings instance
|
# Global settings instance
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
|
||||||
|
# Log configuration values for debugging
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.info(f"JWT Configuration loaded:")
|
||||||
|
logger.info(f"ACCESS_TOKEN_EXPIRE_MINUTES: {settings.ACCESS_TOKEN_EXPIRE_MINUTES}")
|
||||||
|
logger.info(f"REFRESH_TOKEN_EXPIRE_MINUTES: {settings.REFRESH_TOKEN_EXPIRE_MINUTES}")
|
||||||
|
logger.info(f"JWT_ALGORITHM: {settings.JWT_ALGORITHM}")
|
||||||
@@ -51,6 +51,13 @@ def create_access_token(data: Dict[str, Any], expires_delta: Optional[timedelta]
|
|||||||
|
|
||||||
to_encode.update({"exp": expire})
|
to_encode.update({"exp": expire})
|
||||||
encoded_jwt = jwt.encode(to_encode, settings.JWT_SECRET, algorithm=settings.JWT_ALGORITHM)
|
encoded_jwt = jwt.encode(to_encode, settings.JWT_SECRET, algorithm=settings.JWT_ALGORITHM)
|
||||||
|
|
||||||
|
# Log token creation details
|
||||||
|
logger.info(f"Created access token for user {data.get('sub')}")
|
||||||
|
logger.info(f"Token expires at: {expire.isoformat()} (UTC)")
|
||||||
|
logger.info(f"Current UTC time: {datetime.utcnow().isoformat()}")
|
||||||
|
logger.info(f"ACCESS_TOKEN_EXPIRE_MINUTES setting: {settings.ACCESS_TOKEN_EXPIRE_MINUTES}")
|
||||||
|
|
||||||
return encoded_jwt
|
return encoded_jwt
|
||||||
|
|
||||||
def create_refresh_token(data: Dict[str, Any]) -> str:
|
def create_refresh_token(data: Dict[str, Any]) -> str:
|
||||||
@@ -64,10 +71,27 @@ def create_refresh_token(data: Dict[str, Any]) -> str:
|
|||||||
def verify_token(token: str) -> Dict[str, Any]:
|
def verify_token(token: str) -> Dict[str, Any]:
|
||||||
"""Verify JWT token and return payload"""
|
"""Verify JWT token and return payload"""
|
||||||
try:
|
try:
|
||||||
|
# Log current time before verification
|
||||||
|
current_time = datetime.utcnow()
|
||||||
|
logger.info(f"Verifying token at: {current_time.isoformat()} (UTC)")
|
||||||
|
|
||||||
|
# Decode without verification first to check expiration
|
||||||
|
try:
|
||||||
|
unverified_payload = jwt.get_unverified_claims(token)
|
||||||
|
exp_timestamp = unverified_payload.get('exp')
|
||||||
|
if exp_timestamp:
|
||||||
|
exp_datetime = datetime.fromtimestamp(exp_timestamp, tz=None)
|
||||||
|
logger.info(f"Token expiration time: {exp_datetime.isoformat()} (UTC)")
|
||||||
|
logger.info(f"Time until expiration: {(exp_datetime - current_time).total_seconds()} seconds")
|
||||||
|
except Exception as decode_error:
|
||||||
|
logger.warning(f"Could not decode token for expiration check: {decode_error}")
|
||||||
|
|
||||||
payload = jwt.decode(token, settings.JWT_SECRET, algorithms=[settings.JWT_ALGORITHM])
|
payload = jwt.decode(token, settings.JWT_SECRET, algorithms=[settings.JWT_ALGORITHM])
|
||||||
|
logger.info(f"Token verified successfully for user {payload.get('sub')}")
|
||||||
return payload
|
return payload
|
||||||
except JWTError as e:
|
except JWTError as e:
|
||||||
logger.warning(f"Token verification failed: {e}")
|
logger.warning(f"Token verification failed: {e}")
|
||||||
|
logger.warning(f"Current UTC time: {datetime.utcnow().isoformat()}")
|
||||||
raise AuthenticationError("Invalid token")
|
raise AuthenticationError("Invalid token")
|
||||||
|
|
||||||
async def get_current_user(
|
async def get_current_user(
|
||||||
@@ -76,6 +100,10 @@ async def get_current_user(
|
|||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""Get current user from JWT token"""
|
"""Get current user from JWT token"""
|
||||||
try:
|
try:
|
||||||
|
# Log server time for debugging clock sync issues
|
||||||
|
server_time = datetime.utcnow()
|
||||||
|
logger.info(f"get_current_user called at: {server_time.isoformat()} (UTC)")
|
||||||
|
|
||||||
payload = verify_token(credentials.credentials)
|
payload = verify_token(credentials.credentials)
|
||||||
user_id: str = payload.get("sub")
|
user_id: str = payload.get("sub")
|
||||||
if user_id is None:
|
if user_id is None:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { createContext, useContext, useEffect, useState } from "react"
|
import { createContext, useContext, useEffect, useState } from "react"
|
||||||
import { apiClient } from "@/lib/api-client"
|
import { apiClient } from "@/lib/api-client"
|
||||||
|
import { tokenManager } from "@/lib/token-manager"
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string
|
id: string
|
||||||
@@ -39,7 +40,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Check for existing token on mount
|
// Check for existing token on mount
|
||||||
const token = localStorage.getItem("access_token")
|
const token = tokenManager.getAccessToken()
|
||||||
if (token) {
|
if (token) {
|
||||||
// Validate token and get user info
|
// Validate token and get user info
|
||||||
validateToken(token)
|
validateToken(token)
|
||||||
@@ -50,20 +51,10 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
|
|
||||||
const validateToken = async (token: string) => {
|
const validateToken = async (token: string) => {
|
||||||
try {
|
try {
|
||||||
// Temporarily set token in localStorage for apiClient to use
|
|
||||||
const previousToken = localStorage.getItem('token')
|
|
||||||
localStorage.setItem('token', token)
|
|
||||||
|
|
||||||
const userData = await apiClient.get("/api-internal/v1/auth/me")
|
const userData = await apiClient.get("/api-internal/v1/auth/me")
|
||||||
setUser(userData)
|
setUser(userData)
|
||||||
|
|
||||||
// Restore previous token if different
|
|
||||||
if (previousToken && previousToken !== token) {
|
|
||||||
localStorage.setItem('token', previousToken)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
localStorage.removeItem("access_token")
|
tokenManager.clearTokens()
|
||||||
localStorage.removeItem("refresh_token")
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}
|
}
|
||||||
@@ -73,10 +64,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
try {
|
try {
|
||||||
const data = await apiClient.post("/api-internal/v1/auth/login", { username, password })
|
const data = await apiClient.post("/api-internal/v1/auth/login", { username, password })
|
||||||
|
|
||||||
// Store tokens
|
// Store tokens using tokenManager
|
||||||
localStorage.setItem("access_token", data.access_token)
|
tokenManager.setTokens(data.access_token, data.refresh_token)
|
||||||
localStorage.setItem("refresh_token", data.refresh_token)
|
|
||||||
localStorage.setItem("token", data.access_token) // Also set token for apiClient
|
|
||||||
|
|
||||||
// Get user info
|
// Get user info
|
||||||
await validateToken(data.access_token)
|
await validateToken(data.access_token)
|
||||||
@@ -89,10 +78,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
try {
|
try {
|
||||||
const data = await apiClient.post("/api-internal/v1/auth/register", { username, email, password })
|
const data = await apiClient.post("/api-internal/v1/auth/register", { username, email, password })
|
||||||
|
|
||||||
// Store tokens
|
// Store tokens using tokenManager
|
||||||
localStorage.setItem("access_token", data.access_token)
|
tokenManager.setTokens(data.access_token, data.refresh_token)
|
||||||
localStorage.setItem("refresh_token", data.refresh_token)
|
|
||||||
localStorage.setItem("token", data.access_token) // Also set token for apiClient
|
|
||||||
|
|
||||||
// Get user info
|
// Get user info
|
||||||
await validateToken(data.access_token)
|
await validateToken(data.access_token)
|
||||||
@@ -102,22 +89,19 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
localStorage.removeItem("access_token")
|
tokenManager.clearTokens()
|
||||||
localStorage.removeItem("refresh_token")
|
|
||||||
localStorage.removeItem("token") // Also clear token for apiClient
|
|
||||||
setUser(null)
|
setUser(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
const refreshToken = async () => {
|
const refreshToken = async () => {
|
||||||
try {
|
try {
|
||||||
const refresh_token = localStorage.getItem("refresh_token")
|
const refresh_token = tokenManager.getRefreshToken()
|
||||||
if (!refresh_token) {
|
if (!refresh_token) {
|
||||||
throw new Error("No refresh token available")
|
throw new Error("No refresh token available")
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await apiClient.post("/api-internal/v1/auth/refresh", { refresh_token })
|
const data = await apiClient.post("/api-internal/v1/auth/refresh", { refresh_token })
|
||||||
localStorage.setItem("access_token", data.access_token)
|
tokenManager.setTokens(data.access_token, refresh_token)
|
||||||
localStorage.setItem("token", data.access_token) // Also set token for apiClient
|
|
||||||
|
|
||||||
return data.access_token
|
return data.access_token
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user