This file defines API routes for user authentication and authorization processes. It manages user registration, sign-in, password recovery, and password changes, integrating with user services, security utilities, and email notifications.
Scope
Manages user registration by creating new user accounts.
Handles user sign-in and issues access tokens for authenticated sessions.
Facilitates secure password recovery and reset processes.
Allows authenticated users to change their current password.
Ensures user authentication and authorization for protected endpoints.
Imports
APIRouter from fastapi
Initializes the API router for defining authentication-related endpoints and their associated HTTP methods. It groups and manages all authentication routes.
Session from sqlalchemy.orm
Provides database session management, enabling interaction with the underlying database for user data persistence and retrieval operations. It facilitates ORM functionality.
timedelta from datetime
Used to calculate the expiration time for generated access tokens, ensuring time-limited session validity. This prevents indefinite token usage.
get_db from app.core.database
Provides a dependency injection function to obtain a database session for each API request. This ensures proper resource management and transaction handling.
create_access_token, get_token, create_password_reset_token, verify_password_reset_token, verify_password from app.core.security
Essential security utilities for token generation, validation, and password verification within authentication flows. These functions handle cryptographic operations securely.
settings from app.core.config
Accesses application-wide configuration settings, such as access token expiration minutes, for consistent behavior across the authentication module. It centralizes parameters.
UserCreate, UserSignIn, TokenResponse, UserResponse, ForgotPasswordRequest, ResetPasswordRequest, PasswordChangeRequest from app.schemas.schemas
Defines Pydantic models for request and response data, ensuring strict data validation and clear API contracts. These schemas enforce data integrity.
UserService from app.services.service
Provides core business logic for user management, including creation, authentication, retrieval, and password updates. It encapsulates user-related domain operations.
email_service from app.services.email_service
Facilitates sending various email notifications, such as welcome emails and password reset links, to users. It abstracts email sending functionality.
ErrorResponse, SuccessResponse from app.utils.helpers
Provides standardized response models for API operations, ensuring consistent error and success message formatting. This improves API client predictability.
logger from app.core.logging
Integrates logging capabilities to record significant events, errors, and user actions for monitoring and debugging purposes. It provides operational visibility.
Variables
router
An instance of APIRouter that groups and manages all authentication-related API endpoints, applying common prefixes and tags. It organizes the API surface.
Routes
POST /change-password
This route allows an authenticated user to securely change their account password. It validates the old password, updates the database with a new hashed password, and provides appropriate success or error responses based on the operation outcome.
=== " "
Endpoint
POST /change-password
Handler Input Parameters
request (PasswordChangeRequest)
This object contains the old_password and new_password fields provided by the user. It is essential for validating current credentials and setting the updated password securely.
current_user (User)
The current_user object is injected via dependency injection, representing the authenticated user making the request. It provides the id necessary to identify and update the correct user record.
db (Session)
The db object represents the database session, injected via dependency. It facilitates all database operations, including fetching user details and updating the user's hashed password securely.
Request Parameters
old_password (str)
The user's current password, provided in the request body. This field is crucial for verifying the user's identity before allowing any password change operation to proceed.
new_password (str)
The desired new password for the user's account, provided in the request body. This password will be hashed and stored in the database upon successful validation and update.
Response / Output
SuccessResponse (SuccessResponse)
A SuccessResponse object is returned upon successful password change. It contains a confirmation message indicating that the password update operation completed successfully for the user.
Status Codes & Exceptions
404 Not Found: This status is returned if the user_id extracted from the current_user token does not correspond to an existing user in the database. The user cannot be found.
400 Bad Request: This status is returned if the provided old_password does not match the hashed_password stored for the current_user in the database. The current password is incorrect.
500 Internal Server Error: This status is returned for any unexpected server-side errors during the password change process. It indicates a general failure, logged for debugging purposes, preventing successful password update.
Route Logic / Request Processing
Receive POST request at /change-password with request body, current_user, and db session.
Extract user_id from current_user.id.
Retrieve db_user from the database using UserService.get_user_by_id with db and user_id.
Check if db_user is None.
If db_user is None: raise HTTPException with 404 Not Found status and "User not found" detail.
Verify request.old_password against db_user.hashed_password using verify_password.
If verify_password returns False: raise HTTPException with 400 Bad Request status and "Incorrect current password" detail.
Update the user's password in the database using UserService.update_password with db, user_id, and request.new_password.
Log an informational message indicating successful password change for the user's email.
Return a SuccessResponse object with the message "Password changed successfully".
Catch HTTPException and re-raise it.
Catch any other Exception.
Log the error message.
Raise HTTPException with 500 Internal Server Error status and "Error changing password" detail.
Usage Tips
Always ensure the Authorization header contains a valid JWT token for authentication. Without proper authentication, the Depends(get_current_user_from_token) dependency will fail.
Provide both old_password and new_password in the request body. The old_password must exactly match the current password to prevent unauthorized changes.
Additional Notes
This endpoint relies on get_current_user_from_token for user authentication and UserService for database interactions. Ensure these dependencies are correctly configured and accessible.
Password hashing and verification are handled by verify_password and UserService.update_password. The new_password is hashed before storage, enhancing security against data breaches.
POST /signin
POST /signin authenticates a user with provided credentials, generating an access token upon successful verification. It checks for invalid email/password and inactive accounts, returning appropriate HTTP error responses. A TokenResponse object is returned on successful authentication.
=== " "
Endpoint
POST /signin
Handler Input Parameters
user_signin (UserSignIn)
This object contains the user's email and password for authentication. It is used to verify credentials against stored user data to grant access.
db (Session)
This database session dependency is injected for performing database operations. It facilitates user authentication and retrieval of user details from the database for verification.
Request Parameters
email (str)
The user's email address is provided within the UserSignIn request body. This email is crucial for identifying and authenticating the user against the database.
password (str)
The user's password is provided within the UserSignIn request body. This password is crucial for verifying the user's identity in conjunction with the provided email address.
Response / Output
TokenResponse (TokenResponse)
On successful authentication, this object contains the access_token and UserResponse data. It grants authorized access to protected resources.
Status Codes & Exceptions
401 Unauthorized: Returned if UserService.authenticate_user fails to find a matching user or credentials. The detail message indicates "Invalid email or password" to the client.
403 Forbidden: Returned if the authenticated user's is_active status is False. The detail message indicates "User account is inactive" to prevent access.
500 Internal Server Error: Returned for any unexpected Exception during the sign-in process. A generic detail message "Error during sign in" is provided.
Route Logic / Request Processing
Start try block for error handling.
Authenticate user using db, user_signin.email, and user_signin.password via UserService.authenticate_user.
If db_user is None (authentication failed):
Raise HTTPException with 401 Unauthorized status and "Invalid email or password" detail.
If db_user.is_active is False:
Raise HTTPException with 403 Forbidden status and "User account is inactive" detail.
Calculate access_token_expires using settings.ACCESS_TOKEN_EXPIRE_MINUTES.
Create access_token with db_user.id as subject and calculated expiry using create_access_token.
Log successful user sign-in with db_user.email using logger.info.
Return TokenResponse containing access_token and UserResponse from db_user via UserResponse.from_orm.
Handle HTTPException: re-raise the exception.
Handle other Exception types:
Log the error details using logger.error.
Raise HTTPException with 500 Internal Server Error and "Error during sign in" detail.
Usage Tips
Always provide both email and password in the request body. Ensure credentials are correct to avoid 401 Unauthorized errors. Check is_active status for 403 Forbidden.
Handle 401, 403, and 500 responses gracefully in your client application. The access_token is essential for subsequent authenticated requests to protected endpoints.
Additional Notes
This endpoint relies on UserService.authenticate_user for credential verification. The access_token generated has a configurable expiration, requiring client-side refresh logic.
The TokenResponse includes a UserResponse object, providing basic user details alongside the token. This simplifies client-side state management after successful authentication.
POST /reset-password
This route handles password reset requests, verifying the provided token and updating the user's password. It ensures token validity, user existence, and securely updates credentials, returning success or appropriate error responses to the client.
=== " "
Endpoint
POST /reset-password
Handler Input Parameters
request (ResetPasswordRequest)
This ResetPasswordRequest object contains the password reset token and the new password. It is crucial for authenticating the reset and setting the new user credential.
db (Session)
The db parameter represents the database session, injected via Depends(get_db). It provides the necessary connection for user retrieval and password update operations within the database.
Request Parameters
token (string)
The token is a unique string from the ResetPasswordRequest body, used to verify the password reset request's authenticity and validity. It must be current.
new_password (string)
The new_password is the desired new password for the user, provided in the ResetPasswordRequest body. It will replace the user's current password in the database.
Response / Output
SuccessResponse (Object)
A SuccessResponse object is returned upon successful password reset. It contains a confirmation message indicating that the user's password has been updated successfully in the system.
Status Codes & Exceptions
400 Bad Request: Returned if the provided token is invalid or has expired. This prevents unauthorized password changes and ensures only valid reset attempts proceed through the system.
404 Not Found: Returned if the user_id extracted from the valid token payload does not correspond to an existing user in the database. This ensures only registered users can reset.
500 Internal Server Error: Returned for any unexpected server-side error during the password reset process. This indicates a general failure, preventing the password from being updated successfully.
Route Logic / Request Processing
Attempt to execute password reset operations.
Verify the request.token using verify_password_reset_token.
If payload is None (token invalid/expired):
Raise HTTPException with 400 Bad Request and "Invalid or expired token" detail.
Extract user_id from the payload.
Retrieve user from database using UserService.get_user_by_id with db and user_id.
If db_user is None (user not found):
Raise HTTPException with 404 Not Found and "User not found" detail.
Update user's password using UserService.update_password with db, user_id, and request.new_password.
Log successful password reset for the user's email using logger.info.
Return SuccessResponse with "Password reset successfully" message.
If HTTPException occurs within try block:
Re-raise the HTTPException.
If any other Exception occurs:
Log the error using logger.error.
Raise HTTPException with 500 Internal Server Error and "Error resetting password" detail.
Usage Tips
Always ensure the token and new_password are correctly provided in the request body. An invalid or expired token will result in a 400 Bad Request response.
After a successful password reset, the user should be prompted to log in with their new_password. The SuccessResponse confirms the operation's completion.
Additional Notes
This endpoint relies on an external verify_password_reset_token function for token validation. The security of the reset process heavily depends on this function's robustness and implementation.
The UserService handles database interactions for user retrieval and password updates. Any issues with user data or database connectivity will be reflected in the error responses.
POST /forgot-password
This route initiates a password reset process for a user. It verifies the provided email, generates a unique reset token, and dispatches a password reset email. The system handles both existing and non-existent email addresses gracefully and securely.
=== " "
Endpoint
POST /forgot-password
Handler Input Parameters
request (ForgotPasswordRequest)
The ForgotPasswordRequest object contains the user's email address. This object is crucial for identifying the user and initiating the password reset flow within the system.
db (Session)
The db parameter represents the database session dependency. It provides access to the database for user lookup and other data operations required during the password reset process.
Request Parameters
email (str)
The email field is extracted from the ForgotPasswordRequest body. It identifies the user account for which a password reset is requested. This field is essential for user lookup.
Response / Output
SuccessResponse (SuccessResponse)
A SuccessResponse object is returned upon successful processing. It contains a message indicating that a password reset link has been sent if the email exists in the system.
Status Codes & Exceptions
500 Internal Server Error: This status is returned if an unexpected error occurs during the password reset process. It indicates a server-side issue preventing the request from being fully processed successfully.
Route Logic / Request Processing
Receive POST request at /forgot-password endpoint.
Begin try block for error handling.
Retrieve user from database using request.email via UserService.get_user_by_email.
Check if db_user object exists.
If db_user exists:
Create a password reset token using db_user.id via create_password_reset_token.
Send password reset email to db_user.email with db_user.username and reset_token via email_service.send_password_reset_email.
Log an informational message using logger.info about the sent email.
If db_user does not exist:
Log a warning message using logger.warning for the non-existent email.
Return a SuccessResponse with a confirmation message.
If an Exception occurs during the try block:
Log the error details using logger.error.
Raise an HTTPException with 500 Internal Server Error status and a generic detail message.
Usage Tips
Always provide a valid email address in the request body. The system will process the request without revealing if the email exists, enhancing user privacy and security.
Check your email inbox and spam folder for the password reset link. The link is time-sensitive, so use it promptly to reset your account password.
Additional Notes
This endpoint implements a 'blind' password reset mechanism. It confirms receipt without disclosing user existence, which is a standard security practice to prevent user enumeration attacks.
The create_password_reset_token and email_service.send_password_reset_email functions are external dependencies. Their successful operation is critical for the password reset functionality.
POST /signup
This route registers a new user, validating email and username uniqueness. It creates the user, generates an access token, and sends a welcome email upon successful registration.
=== " "
400.
400.
Endpoint
POST /signup
Handler Input Parameters
user_create (UserCreate)
Pydantic model containing new user's registration data, including email and username. This object is used to create the new user record.
db (Session)
Database session dependency injected into the route handler. This session facilitates all database operations, including user retrieval and creation.
Request Parameters
email (string)
Email address provided in the UserCreate body. This field is validated for uniqueness against existing users in the database during signup.
username (string)
Username provided in the UserCreate body. This field is validated for uniqueness against existing usernames in the database during signup.
Response / Output
TokenResponse (TokenResponse)
Response object containing the generated access_token and the newly created UserResponse object. This is returned upon successful user registration.
Status Codes & Exceptions
201 Created: Returned upon successful user registration. The response body contains the TokenResponse object, including the access token and user details.
400 Bad Request: Returned if the provided email is already registered or the username is already taken. Specific detail messages indicate the exact conflict reason.
500 Internal Server Error: Returned for any unexpected server-side errors during the registration process. A generic 'Error during registration' message is provided.
Route Logic / Request Processing
Receive POST request with UserCreate data and database session.
Attempt to retrieve an existing user by the provided email.
If an existing user is found with that email: raise HTTPException with 400 status and 'Email already registered' detail.
Attempt to retrieve an existing user by the provided username.
If an existing user is found with that username: raise HTTPException with 400 status and 'Username already taken' detail.
Create a new user in the database using the UserCreate data.
Calculate access token expiration time.
Generate a new access token for the newly created user.
Send a welcome email to the new user's registered email address.
Log successful user registration with the user's email.
Return a TokenResponse object containing the access token and the new user's details.
If an HTTPException occurs during the process: re-raise the exception.
If any other Exception occurs: log the error and raise HTTPException with 500 status and 'Error during registration' detail.
Usage Tips
Always ensure the email and username fields in your request body are unique. Duplicate values will result in a 400 Bad Request error response.
Upon successful registration, store the returned access_token securely. This token is essential for authenticating subsequent requests to protected endpoints.
Additional Notes
This endpoint performs multiple database lookups for uniqueness before user creation. This ensures data integrity and prevents duplicate user entries effectively.
A welcome email is dispatched asynchronously after successful registration. The 500 Internal Server Error handles unexpected issues, providing a generic error message.
Routers
router
This `router` centralizes authentication API endpoints, managing user lifecycle and token validation. It secures application access by handling user credentials and session management. This module integrates seamlessly, providing robust authentication.
Prefix
/api/v1/auth
Configuration Details
Tags
Authentication
Functions
get_current_user_from_token
public
This function retrieves the currently authenticated user's object from the database using a provided token payload. It ensures the user exists based on the `user_id` extracted from the token, facilitating secure access to protected resources and user-specific data.
This dictionary contains decoded information from the authentication token, including the sub (subject) field representing the user's unique identifier. It is crucial for identifying the authenticated user.
db (Session)
The SQLAlchemy database session provides the necessary connection to interact with the database. It enables fetching user details based on the extracted user_id, ensuring data persistence and retrieval operations.
Output / Return Values
user (User)
The User object represents the authenticated user found in the database. This object contains all relevant user details, which can then be used by subsequent operations requiring user context.
Exceptions
HTTPException 404 Not Found[404]
Raised when no user is found in the database corresponding to the user_id extracted from the token_payload. This indicates an invalid or expired user reference.
Logic / Execution Flow
Extract the user_id from the token_payload dictionary using the key "sub", converting it to an integer.
Call UserService.get_user_by_id with the database session db and the extracted user_id to retrieve the user object.
Check if the user object returned from the service call is None (i.e., no user was found).
If user is None (user not found):
Raise an HTTPException with a status_code of 404 and detail message "User not found".
If user is found:
Return the retrieved user object.
Usage Tips
Always ensure the get_token dependency correctly validates and decodes the authentication token before passing the token_payload. This prevents processing invalid or malicious tokens.
Integrate this dependency into FastAPI route functions that require authenticated user context. This pattern simplifies access control and ensures only valid users can perform specific actions.
Additional Notes
The UserService.get_user_by_id call is critical; its performance directly impacts this function's efficiency. Ensure the underlying database query is optimized for quick user retrieval.
This function assumes token_payload always contains a valid sub key. Robust token generation should guarantee this, but consider adding more explicit validation for sub if token sources are varied.
FAQs
Why are UserService and email_service injected rather than instantiated directly?
Dependency injection promotes loose coupling and testability by allowing external services to be provided at runtime. This design facilitates easier mocking during testing and flexible service configuration.
What is the purpose of using Pydantic schemas for request and response bodies?
Pydantic schemas provide robust data validation and serialization, ensuring that incoming request data conforms to expected structures and outgoing responses are consistently formatted. This enhances API reliability.
How does the system ensure that password reset tokens are secure and time-limited?
Password reset tokens are cryptographically signed and include an expiration timestamp. The verify_password_reset_token function validates both the signature and the expiration, preventing token reuse or tampering.
Insights
Metric
Score
Level
Complexity
1.00
Very Complex
Security
1.00
Secure
Performance
0.75
Acceptable Performance
Complexity
Medium - Repetitive Error Handling Logic
Error handling for HTTPException and generic Exception is duplicated across multiple route functions. Centralizing this logic could improve maintainability and reduce boilerplate.
Security
High - Missing Rate Limiting for Authentication Endpoints
The authentication endpoints lack explicit rate limiting, making them vulnerable to brute-force attacks on login or password reset attempts. This could lead to account compromise.