feat: Implement custom bearer token security dependency for authentication
CI / skip-ci-check (push) Successful in 1m28s
CI / skip-ci-check (pull_request) Successful in 1m28s
CI / python-lint (push) Has been cancelled
CI / test-backend (push) Has been cancelled
CI / build (push) Has been cancelled
CI / secret-scanning (push) Has been cancelled
CI / dependency-scan (push) Has been cancelled
CI / sast-scan (push) Has been cancelled
CI / workflow-summary (push) Has been cancelled
CI / lint-and-type-check (push) Has been cancelled
CI / lint-and-type-check (pull_request) Successful in 2m6s
CI / python-lint (pull_request) Successful in 1m53s
CI / test-backend (pull_request) Successful in 3m12s
CI / build (pull_request) Successful in 2m25s
CI / secret-scanning (pull_request) Successful in 1m41s
CI / dependency-scan (pull_request) Successful in 1m35s
CI / sast-scan (pull_request) Successful in 2m49s
CI / workflow-summary (pull_request) Successful in 1m27s
CI / skip-ci-check (push) Successful in 1m28s
CI / skip-ci-check (pull_request) Successful in 1m28s
CI / python-lint (push) Has been cancelled
CI / test-backend (push) Has been cancelled
CI / build (push) Has been cancelled
CI / secret-scanning (push) Has been cancelled
CI / dependency-scan (push) Has been cancelled
CI / sast-scan (push) Has been cancelled
CI / workflow-summary (push) Has been cancelled
CI / lint-and-type-check (push) Has been cancelled
CI / lint-and-type-check (pull_request) Successful in 2m6s
CI / python-lint (pull_request) Successful in 1m53s
CI / test-backend (pull_request) Successful in 3m12s
CI / build (pull_request) Successful in 2m25s
CI / secret-scanning (pull_request) Successful in 1m41s
CI / dependency-scan (pull_request) Successful in 1m35s
CI / sast-scan (pull_request) Successful in 2m49s
CI / workflow-summary (pull_request) Successful in 1m27s
This commit introduces a custom security dependency, `get_bearer_token`, in the authentication API to ensure compliance with HTTP standards by returning a 401 Unauthorized status for missing or invalid tokens. Additionally, it updates test user fixtures to include full names for better clarity in tests.
This commit is contained in:
+44
-4
@@ -6,8 +6,8 @@ import os
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
from fastapi.security import HTTPAuthorizationCredentials
|
||||
from jose import JWTError, jwt
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -30,7 +30,47 @@ from backend.schemas.auth import (
|
||||
from backend.services.role_permissions import fetch_role_permissions_map
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
security = HTTPBearer()
|
||||
|
||||
|
||||
def get_bearer_token(request: Request) -> HTTPAuthorizationCredentials:
|
||||
"""Custom security dependency that returns 401 for missing tokens (not 403).
|
||||
|
||||
This replaces HTTPBearer() to follow HTTP standards where missing authentication
|
||||
should return 401 Unauthorized, not 403 Forbidden.
|
||||
"""
|
||||
authorization = request.headers.get("Authorization")
|
||||
if not authorization:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Not authenticated",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
# Parse Authorization header: "Bearer <token>"
|
||||
parts = authorization.split(" ", 1)
|
||||
if len(parts) != 2:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid authentication scheme",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
scheme, credentials = parts
|
||||
if scheme.lower() != "bearer":
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid authentication scheme",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
if not credentials:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid authentication credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
return HTTPAuthorizationCredentials(scheme=scheme, credentials=credentials)
|
||||
|
||||
# Placeholder secrets - replace with env vars in production
|
||||
SECRET_KEY = "dev-secret-key-change-in-production"
|
||||
@@ -60,7 +100,7 @@ def create_refresh_token(data: dict) -> str:
|
||||
|
||||
|
||||
def get_current_user(
|
||||
credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)]
|
||||
credentials: Annotated[HTTPAuthorizationCredentials, Depends(get_bearer_token)]
|
||||
) -> dict:
|
||||
"""Get current user from JWT token."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user