""" Authentication API endpoints Provides login, logout, token refresh, and current user endpoints. """ from flask import jsonify, request from app.api import api_bp from app.services import AuthService, login_required, get_current_user_from_context from app.errors import ValidationError @api_bp.route('/auth/login', methods=['POST']) def login(): """ User login endpoint Request body: { "username": "string", "password": "string" } Returns: { "token": "access_token", "refresh_token": "refresh_token", "user": { user object } } """ data = request.get_json() if not data: raise ValidationError( message="Request body is required", details={"reason": "missing_body"} ) username = data.get('username') password = data.get('password') if not username or not password: raise ValidationError( message="Username and password are required", details={ "missing_fields": [ field for field in ['username', 'password'] if not data.get(field) ] } ) user, tokens = AuthService.authenticate(username, password) return jsonify({ 'token': tokens['access_token'], 'refresh_token': tokens['refresh_token'], 'user': user.to_dict() }), 200 @api_bp.route('/auth/logout', methods=['POST']) @login_required def logout(): """ User logout endpoint Note: Since JWT is stateless, logout is handled client-side by removing the token. This endpoint exists for API consistency and can be extended for token blacklisting. Returns: { "message": "Logged out successfully" } """ # In a stateless JWT system, logout is handled client-side # This endpoint can be extended to implement token blacklisting if needed return jsonify({ 'message': 'Logged out successfully' }), 200 @api_bp.route('/auth/me', methods=['GET']) @login_required def get_current_user(): """ Get current authenticated user information Returns: { user object } """ user = get_current_user_from_context() return jsonify(user.to_dict()), 200 @api_bp.route('/auth/refresh', methods=['POST']) def refresh_token(): """ Refresh access token using refresh token Request body: { "refresh_token": "string" } Returns: { "access_token": "new_access_token" } """ data = request.get_json() if not data: raise ValidationError( message="Request body is required", details={"reason": "missing_body"} ) refresh_token_value = data.get('refresh_token') if not refresh_token_value: raise ValidationError( message="Refresh token is required", details={"missing_fields": ["refresh_token"]} ) tokens = AuthService.refresh_access_token(refresh_token_value) return jsonify({ 'access_token': tokens['access_token'] }), 200