| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- """
- 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
|