Overview
The Water Quality Backend API uses JWT (JSON Web Tokens) for authentication, backed by Firebase Authentication for credential verification and user management. The API also supports GitHub OAuth for social login.
Authentication Methods
The API supports three authentication methods:
Email/Password : Traditional registration and login
GitHub OAuth : Social login via GitHub
Password Reset : Secure password recovery flow
Registration
Create a new user account with email and password.
Endpoint
Request Body
{
"email" : "[email protected] " ,
"username" : "john_doe" ,
"password" : "SecurePass123!" ,
"phone" : "+1234567890" // optional
}
Response
{
"message" : "Registered successfully"
}
Example with cURL
curl -X POST https://api.example.com/auth/register/ \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected] ",
"username": "john_doe",
"password": "SecurePass123!"
}'
The user is automatically created in Firebase Authentication and assigned the CLIENT role by default.
Login
Authenticate with email and password to receive a JWT access token.
Endpoint
Request Body
Response
{
"message" : "Logged in successfully" ,
"user" : {
"uid" : "firebase_uid_123" ,
"email" : "[email protected] " ,
"username" : "john_doe" ,
"phone" : "+1234567890" ,
"rol" : "client"
},
"token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Example with cURL
curl -X POST https://api.example.com/auth/login/ \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected] ",
"password": "SecurePass123!"
}'
Authentication Flow
Submit Credentials
Client sends email and password to /auth/login/
Verify with Firebase
Backend verifies credentials using Firebase Authentication API: POST https: // identitytoolkit.googleapis.com / v1 / accounts:signInWithPassword ? key = { API_KEY }
Generate JWT Token
If credentials are valid, create a JWT token with user payload: payload = {
"uid" : user.uid,
"email" : user.email,
"username" : user.username,
"phone" : user.phone,
"rol" : user.rol,
"exp" : time.time() + 2592000 # 30 days
}
token = jwt.encode(payload, SECRET_KEY , algorithm = 'HS256' )
Return Token
Send JWT token to client along with user data
Using Access Tokens
Once authenticated, include the JWT token in the Authorization header for all protected endpoints.
Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Example Request
curl -X GET https://api.example.com/workspaces/ \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Token Verification
Protected endpoints verify the token using the AccessToken service:
from app.share.jwt.infrastructure.access_token import AccessToken
access_token = AccessToken()
payload = access_token.validate(token)
# Returns: {"uid": "...", "email": "...", "username": "...", "rol": "...", "exp": ...}
Tokens expire after 30 days (2,592,000 seconds). Clients should handle token expiration and re-authenticate.
JWT Token Structure
Payload
The JWT token contains the following claims:
{
"uid" : "firebase_uid_123" ,
"email" : "[email protected] " ,
"username" : "john_doe" ,
"phone" : "+1234567890" ,
"rol" : "client" ,
"exp" : 1709654400
}
Claims Description
uid : Firebase user ID (unique identifier)
email : User’s email address
username : User’s display name
phone : User’s phone number (optional)
rol : User role (client, admin, etc.)
exp : Expiration timestamp (Unix epoch)
Algorithm
Tokens are signed using HS256 (HMAC with SHA-256) with the SECRET_KEY from environment variables.
GitHub OAuth
The API supports GitHub OAuth for seamless social login.
OAuth Flow
Initiate OAuth
Redirect user to GitHub authorization: GET /auth/github/login/web
or for mobile apps: GET /auth/github/login/mobile
GitHub Authorization
User authorizes the app on GitHub and is redirected back to: /auth/github/callback?code=...&state=...
Exchange Code for Token
Backend exchanges the authorization code for a GitHub access token: POST https: // github.com / login / oauth / access_token
{
"client_id" : GITHUB_CLIENT_ID ,
"client_secret" : GITHUB_CLIENT_SECRET ,
"code" : code,
"redirect_uri" : GITHUB_CALLBACK_URL
}
Fetch User Profile
Retrieve user information from GitHub: GET https: // api.github.com / user
GET https: // api.github.com / user / emails
Create or Login User
If user doesn’t exist, create account with GitHub email/username.
If user exists, log them in.
Redirect with Token
Redirect to frontend with JWT token:
Web : {FRONTEND_ORIGIN}?token=...&email=...&username=...
Mobile : aquaminds://login-success?token=...&code=...
Web OAuth Example
# Step 1: Redirect user to GitHub login
curl -L https://api.example.com/auth/github/login/web
# Step 2: User authorizes on GitHub
# Step 3: User is redirected to frontend with token
https://app.example.com?token =eyJhbG. .. & email = [email protected] & username = john_doe & rol = client & uid = abc123
Mobile OAuth Example
# Step 1: Redirect user to GitHub login
curl -L https://api.example.com/auth/github/login/mobile
# Step 2: User authorizes on GitHub
# Step 3: User is redirected to mobile app via deep link
aquaminds://login-success?token =eyJhbG. .. & code = github_code
State Parameter Security
The OAuth flow uses a signed state parameter to prevent CSRF attacks:
state_payload = {
"redirect_uri" : FRONTEND_ORIGIN ,
"exp" : int (time.time()) + 600 # 10 minutes
}
state = sign_state(state_payload) # HMAC-signed with STATE_SECRET
The state is verified on callback to ensure authenticity.
Security : The STATE_SECRET environment variable must be set for OAuth to work. This secret is used to sign and verify the state parameter.
Password Reset Flow
Secure password recovery using email verification codes.
Step 1: Request Password Reset
POST /auth/request-password-reset/
Request :
Response :
{
"message" : "Código de verificación enviado"
}
This generates a 6-digit verification code stored in Firebase Realtime Database with a 10-minute expiration :
reset_code = random.randint( 100000 , 999999 )
expire_date = datetime.now() + timedelta( minutes = 10 )
db.reference( f "/password_reset/ { user.uid } " ).set({
"code" : reset_code,
"expires" : expire_date.timestamp()
})
The code is sent to the user’s email via Resend API .
Step 2: Verify Reset Code
POST /auth/verify-reset-code/
Request :
Response :
{
"message" : "Código de verificación válido" ,
"token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
This validates the code and returns a short-lived token for password reset.
Step 3: Reset Password
POST /auth/reset-password/?token={reset_token}
Request :
{
"new_password" : "NewSecurePass123!"
}
Response :
{
"message" : "Contraseña actualizada con éxito" ,
"user" : {
"uid" : "firebase_uid_123" ,
"email" : "[email protected] " ,
"username" : "john_doe"
}
}
Complete Password Reset Example
# Step 1: Request reset
curl -X POST https://api.example.com/auth/request-password-reset/ \
-H "Content-Type: application/json" \
-d '{"email": "[email protected] "}'
# Step 2: Verify code from email
curl -X POST https://api.example.com/auth/verify-reset-code/ \
-H "Content-Type: application/json" \
-d '{"email": "[email protected] ", "code": 123456}'
# Returns: {"message": "...", "token": "xyz..."}
# Step 3: Reset password with token
curl -X POST 'https://api.example.com/auth/reset-password/?token=xyz...' \
-H "Content-Type: application/json" \
-d '{"new_password": "NewSecurePass123!"}'
User Roles
The API supports role-based access control (RBAC):
client : Standard user (default)
admin : Administrative privileges
Roles are stored in the JWT token and can be used for authorization:
from app.share.jwt.infrastructure.access_token import AccessToken
def get_current_user ( token : str = Depends(oauth2_scheme)):
payload = AccessToken().validate(token)
if payload[ "rol" ] != "admin" :
raise HTTPException( status_code = 403 , detail = "Admin access required" )
return payload
Environment Configuration
Authentication requires the following environment variables:
Secret key for signing JWT tokens (HS256 algorithm)
Firebase API key for authentication requests
GitHub OAuth app client ID
GitHub OAuth app client secret
OAuth callback URL (e.g., https://api.example.com/auth/github/callback)
Frontend URL for web OAuth redirects (e.g., https://app.example.com/oauth/callback)
Secret for HMAC-signing OAuth state parameter (prevent CSRF)
Mobile app deep link scheme (default: aquaminds://login-success)
See the Environment Variables guide for complete configuration.
Error Handling
The authentication endpoints return standard HTTP error codes:
Status Code Description 400Invalid request body or parameters 401Invalid credentials or expired token 404User not found 500Server error or Firebase error 502GitHub API communication error 504GitHub API timeout
Example Error Response
{
"detail" : "Credenciales inválidas"
}
Security Best Practices
Never expose SECRET_KEY : Keep your JWT secret key secure and never commit it to version control.
Use HTTPS : Always use HTTPS in production to prevent token interception.
Recommendations
Rotate Secrets : Periodically rotate SECRET_KEY and STATE_SECRET
Short Expiration : Consider shorter token expiration for sensitive applications
Refresh Tokens : Implement refresh tokens for better security (currently not implemented)
Rate Limiting : Add rate limiting to prevent brute force attacks
Password Complexity : Enforce strong password requirements
Email Verification : Consider adding email verification for new registrations
Next Steps
Environment Variables Configure Firebase, GitHub OAuth, and other auth settings
API Reference Explore all authentication endpoints in detail