diff --git a/fastapi_cloudauth/firebase.py b/fastapi_cloudauth/firebase.py index 12f6353..3e5bb21 100644 --- a/fastapi_cloudauth/firebase.py +++ b/fastapi_cloudauth/firebase.py @@ -1,7 +1,7 @@ from calendar import timegm from datetime import datetime from email.utils import parsedate_to_datetime -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional, Set import requests from fastapi import HTTPException @@ -39,6 +39,7 @@ def _set_expiration(self, resp: requests.Response) -> Optional[datetime]: class FirebaseClaims(BaseModel): user_id: str = Field(alias="user_id") email: str = Field(None, alias="email") + scope: str = Field(None) class FirebaseCurrentUser(UserInfoAuth): @@ -48,7 +49,7 @@ class FirebaseCurrentUser(UserInfoAuth): user_info = FirebaseClaims - def __init__(self, project_id: str, *args: Any, **kwargs: Any): + def __init__(self, project_id: str, required_scopes: Set[str] = {}, *args: Any, **kwargs: Any): url = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com" jwks = JWKS(url=url) super().__init__( @@ -57,17 +58,31 @@ def __init__(self, project_id: str, *args: Any, **kwargs: Any): user_info=self.user_info, audience=project_id, issuer=f"https://securetoken.google.com/{project_id}", - extra=FirebaseExtraVerifier(project_id=project_id), + extra=FirebaseExtraVerifier( + project_id=project_id, + required_scopes=required_scopes + ), **kwargs, ) class FirebaseExtraVerifier(ExtraVerifier): - def __init__(self, project_id: str): + def __init__(self, project_id: str, required_scopes: Set[str]): self._pjt_id = project_id + self.required_scopes = required_scopes def __call__(self, claims: Dict[str, str], auto_error: bool = True) -> bool: # auth_time must be past time + scopes_str = claims.get("scope") + + scopes = scopes_str.split(' ') if scopes_str is not None else {} + + for required_scope in self.required_scopes: + if required_scope not in scopes: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, detail=NOT_VERIFIED + ) + if claims.get("auth_time"): auth_time = int(claims["auth_time"]) now = timegm(datetime.utcnow().utctimetuple()) diff --git a/pyproject.toml b/pyproject.toml index 857a841..bfff636 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,5 +53,5 @@ profile = "black" known_third_party = ["fastapi", "pydantic", "starlette"] [build-system] -requires = ["poetry>=1.1.12"] -build-backend = "poetry.masonry.api" +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" \ No newline at end of file