diff --git a/python/across_api/across/api.py b/python/across_api/across/api.py index e7ea6396c..70867561c 100644 --- a/python/across_api/across/api.py +++ b/python/across_api/across/api.py @@ -4,9 +4,10 @@ from typing import Annotated, Optional -from fastapi import Depends, Query +from fastapi import Depends, Query, Security from ..base.api import app +from ..auth.api import scope_authorize from .hello import Hello from .resolve import Resolve from .schema import HelloSchema, ResolveSchema @@ -47,6 +48,20 @@ def hello(name: YourNameDep) -> HelloSchema: return Hello(name=name).schema +@app.get( + "/secure_hello", + dependencies=[ + Security(scope_authorize, scopes=["gcn.nasa.gov/kafka-public-consumer"]) + ], +) +async def secure_hello(name: YourNameDep) -> HelloSchema: + """ + This function returns a JSON response with a greeting message and an optional name parameter. + If the name parameter is provided, the greeting message will include the name. + """ + return Hello(name=name).schema + + @app.get("/across/resolve") def resolve(name: SourceNameDep) -> ResolveSchema: """ diff --git a/python/across_api/auth/api.py b/python/across_api/auth/api.py index c4b8010de..fe3b9a87a 100644 --- a/python/across_api/auth/api.py +++ b/python/across_api/auth/api.py @@ -9,8 +9,8 @@ from jose import jwt from jose.exceptions import JWTError import httpx # type: ignore -from fastapi import Depends, HTTPException -from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer +from fastapi import Depends, HTTPException, Security +from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer, SecurityScopes from ..base.api import app from .schema import VerifyAuth @@ -77,10 +77,26 @@ async def claims( raise HTTPException(status_code=401, detail=f"Authentication error: {e}") -JWTBearerDep = [Depends(claims)] +async def scope_authorize( + security_scopes: SecurityScopes, + access_token: Annotated[dict, Depends(claims)], +): + # retrieve scopes from access token + scopes = access_token.get("scope", "") + # assuming the jwt scopes will be comma separated + token_scopes = scopes.split(",") -@app.get("/auth/verify", dependencies=JWTBearerDep) + # raise exception if user.role not in endpoint scope + if not all(scope in token_scopes for scope in security_scopes.scopes): + raise HTTPException( + status_code=401, + detail="Bearer token scope(s) not in endpoint scope", + headers={"WWW-Authenticate": "Bearer"}, + ) + + +@app.get("/auth/verify", dependencies=[Security(scope_authorize, scopes=[])]) async def verify_authentication() -> VerifyAuth: """Verify that the user is authenticated.""" return VerifyAuth()