diff --git a/mnemo_cards_backend/lib/api/v2/admin_auth_api_v2.dart b/mnemo_cards_backend/lib/api/v2/admin_auth_api_v2.dart index 6c1b16e..3a0a452 100644 --- a/mnemo_cards_backend/lib/api/v2/admin_auth_api_v2.dart +++ b/mnemo_cards_backend/lib/api/v2/admin_auth_api_v2.dart @@ -159,7 +159,9 @@ class AdminAuthApiV2 { } // Generate JWT token using JwtService (same as regular auth) + print('[ADMIN AUTH] Generating tokens for admin user ${user.id}'); final tokens = await _jwtService.generateTokens(user); + print('[ADMIN AUTH] Generated access token, length: ${tokens.accessToken.length}'); return _json({ 'success': true, diff --git a/mnemo_cards_backend/lib/api/v2/authorize_v2.dart b/mnemo_cards_backend/lib/api/v2/authorize_v2.dart index 485e101..89bec66 100644 --- a/mnemo_cards_backend/lib/api/v2/authorize_v2.dart +++ b/mnemo_cards_backend/lib/api/v2/authorize_v2.dart @@ -112,9 +112,28 @@ Middleware authorizeV2(UserManager userManager, JwtService jwtService) { } final token = authHeader.substring(7); // Remove "Bearer " prefix + + // Debug logging for admin endpoints + if (normalizedPath.startsWith('/admin/')) { + print('[AUTH DEBUG] Verifying token for path: $normalizedPath'); + print('[AUTH DEBUG] Token length: ${token.length}'); + print('[AUTH DEBUG] Token preview: ${token.length > 50 ? token.substring(0, 50) + "..." : token}'); + } + final userId = jwtService.verifyAccessToken(token); if (userId == null) { + // Additional debug info for admin endpoints + if (normalizedPath.startsWith('/admin/')) { + print('[AUTH DEBUG] Token verification failed for path: $normalizedPath'); + // Try to extract payload to see what's wrong + try { + final payload = jwtService.extractPayload(token); + print('[AUTH DEBUG] Extracted payload: $payload'); + } catch (e) { + print('[AUTH DEBUG] Could not extract payload: $e'); + } + } return Response( 401, headers: {'Content-Type': 'application/json'}, diff --git a/mnemo_cards_backend/lib/api/v2/jwt_service.dart b/mnemo_cards_backend/lib/api/v2/jwt_service.dart index cf9d42e..621b988 100644 --- a/mnemo_cards_backend/lib/api/v2/jwt_service.dart +++ b/mnemo_cards_backend/lib/api/v2/jwt_service.dart @@ -46,6 +46,10 @@ class JwtService { // Create JWT tokens with proper HMAC-SHA256 signing final accessToken = _createSimpleJwt(accessTokenPayload); final refreshToken = _createSimpleJwt(refreshTokenPayload); + + print('[JWT DEBUG] Generated access token for user ${user.id}'); + print('[JWT DEBUG] Access token payload: $accessTokenPayload'); + print('[JWT DEBUG] Access token length: ${accessToken.length}'); // Store refresh token for invalidation final userId = user.id; @@ -66,24 +70,38 @@ class JwtService { String? verifyAccessToken(String token) { try { final payload = _verifySimpleJwt(token); - if (payload == null) return null; + if (payload == null) { + print('[JWT DEBUG] Token verification failed: payload is null'); + return null; + } + + print('[JWT DEBUG] Token payload: $payload'); // Check if token is expired final exp = payload['exp'] as int?; if (exp != null) { final expiryTime = DateTime.fromMillisecondsSinceEpoch(exp * 1000); - if (DateTime.now().isAfter(expiryTime)) { + final now = DateTime.now(); + print('[JWT DEBUG] Token expiry: $expiryTime, now: $now, expired: ${now.isAfter(expiryTime)}'); + if (now.isAfter(expiryTime)) { + print('[JWT DEBUG] Token is expired'); return null; } } // Check token type - if (payload['type'] != 'access') { + final tokenType = payload['type']; + print('[JWT DEBUG] Token type: $tokenType'); + if (tokenType != 'access') { + print('[JWT DEBUG] Token type mismatch: expected "access", got "$tokenType"'); return null; } - return payload['userId']?.toString(); + final userId = payload['userId']?.toString(); + print('[JWT DEBUG] Extracted userId: $userId'); + return userId; } catch (e) { + print('[JWT DEBUG] Token verification exception: $e'); return null; } } @@ -143,7 +161,10 @@ class JwtService { Map? _verifySimpleJwt(String token) { try { final parts = token.split('.'); - if (parts.length != 3) return null; + if (parts.length != 3) { + print('[JWT DEBUG] Invalid token format: expected 3 parts, got ${parts.length}'); + return null; + } final headerB64 = parts[0]; final payloadB64 = parts[1]; @@ -156,13 +177,19 @@ class JwtService { final expectedSignatureB64 = base64UrlEncode(expectedSignature); if (signatureB64 != expectedSignatureB64) { + print('[JWT DEBUG] Invalid signature'); + print('[JWT DEBUG] Expected: $expectedSignatureB64'); + print('[JWT DEBUG] Got: $signatureB64'); return null; // Invalid signature } // Decode payload final payloadJson = utf8.decode(base64Url.decode(payloadB64)); - return jsonDecode(payloadJson) as Map; + final payload = jsonDecode(payloadJson) as Map; + print('[JWT DEBUG] Decoded payload: $payload'); + return payload; } catch (e) { + print('[JWT DEBUG] Exception during token verification: $e'); return null; } }