80 lines
2.8 KiB
Python
80 lines
2.8 KiB
Python
# Copyright 2026 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
|
from app.auth.jwt_handler import create_access_token, get_current_user
|
|
from app.auth.otp_service import otp_service
|
|
from app.config import settings
|
|
from app.schemas.auth_schema import (
|
|
OTPRequest,
|
|
OTPRequestResponse,
|
|
OTPVerify,
|
|
SessionValidationResponse,
|
|
TokenResponse,
|
|
UserResponse,
|
|
)
|
|
|
|
router = APIRouter(prefix="/api/v1/auth", tags=["Authentication & Verification"])
|
|
|
|
|
|
@router.post("/otp/send", response_model=OTPRequestResponse)
|
|
async def request_otp(payload: OTPRequest):
|
|
"""Request an OTP verification code sent to phone/email."""
|
|
code = otp_service.generate_otp(payload.identifier)
|
|
return OTPRequestResponse(
|
|
message="Verification code dispatched successfully",
|
|
identifier=payload.identifier,
|
|
expires_in_seconds=settings.OTP_EXPIRE_SECONDS,
|
|
)
|
|
|
|
|
|
@router.post("/otp/verify", response_model=TokenResponse)
|
|
async def verify_otp(payload: OTPVerify):
|
|
"""Verify OTP callback and return signed JWT session token."""
|
|
valid = otp_service.verify_otp(payload.identifier, payload.code)
|
|
if not valid:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
detail="Invalid or expired verification code",
|
|
)
|
|
|
|
# Issue JWT token
|
|
token = create_access_token(user_id=payload.identifier)
|
|
return TokenResponse(
|
|
access_token=token,
|
|
token_type="bearer",
|
|
user_id=payload.identifier,
|
|
expires_in=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES * 60,
|
|
)
|
|
|
|
|
|
@router.get("/me", response_model=UserResponse)
|
|
async def get_current_user_profile(user_id: str = Depends(get_current_user)):
|
|
"""Retrieve authenticated user identity."""
|
|
return UserResponse(user_id=user_id, authenticated=True)
|
|
|
|
|
|
@router.get("/validate-session", response_model=SessionValidationResponse)
|
|
async def validate_session_ingress(
|
|
session_id: str = Query(..., description="Target session UUID"),
|
|
user_id: str = Depends(get_current_user),
|
|
):
|
|
"""Used by Nginx auth_request to confirm user has permission for a specific session."""
|
|
return SessionValidationResponse(
|
|
valid=True,
|
|
user_id=user_id,
|
|
session_id=session_id,
|
|
message="Access authorized",
|
|
)
|