Skip to content

Commit fbd07bc

Browse files
committed
Simplify session token usage
1 parent ca947ca commit fbd07bc

File tree

3 files changed

+31
-34
lines changed

3 files changed

+31
-34
lines changed

fastapiauthenticator/service.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,6 @@ def __init__(
5959
elif isinstance(params, models.Parameters):
6060
self.params = [params]
6161

62-
self.route_map: Dict[str, models.Parameters] = {
63-
param.path: param for param in self.params if param.route is APIRoute
64-
}
65-
6662
models.fallback.path = fallback_path
6763
models.fallback.button = fallback_button
6864

@@ -95,19 +91,18 @@ def _verify_auth(
9591
Dict[str, str]:
9692
A dictionary containing the redirect URL to the secure path.
9793
"""
98-
utils.verify_login(
94+
session_token = utils.verify_login(
9995
authorization=authorization,
10096
request=request,
10197
env_username=self.username,
10298
env_password=self.password,
10399
)
104-
destination = request.cookies.get("X-Requested-By")
105-
if parameter := self.route_map.get(destination):
100+
if destination := request.cookies.get("X-Requested-By"):
106101
LOGGER.info("Setting session timeout for %s seconds", self.timeout)
107102
# Set session_token cookie with a timeout, to be used for session validation when redirected
108103
response.set_cookie(
109104
key="session_token",
110-
value=models.ws_session.client_auth[request.client.host].get("token"),
105+
value=session_token,
111106
httponly=True,
112107
samesite="strict",
113108
max_age=self.timeout,
@@ -118,7 +113,7 @@ def _verify_auth(
118113
args=(request.client.host,),
119114
interval=self.timeout,
120115
).start()
121-
return {"redirect_url": parameter.path}
116+
return {"redirect_url": destination}
122117
raise HTTPException(
123118
status_code=status.HTTP_417_EXPECTATION_FAILED,
124119
detail="Unable to find secure route for the requested path.\n"
@@ -154,14 +149,14 @@ def _secure(self) -> None:
154149
secure_route = APIWebSocketRoute(
155150
path=param.path,
156151
endpoint=param.function,
157-
dependencies=[Depends(utils.session_check)],
152+
dependencies=[Depends(utils.verify_session)],
158153
)
159154
else:
160155
secure_route = APIRoute(
161156
path=param.path,
162157
endpoint=param.function,
163158
methods=["GET"],
164-
dependencies=[Depends(utils.session_check)],
159+
dependencies=[Depends(utils.verify_session)],
165160
)
166161
self.app.routes.append(secure_route)
167162
self.app.routes.extend([login_route, session_route, verify_route, error_route])

fastapiauthenticator/utils.py

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22
import secrets
3-
from typing import Dict, List, NoReturn, Union
3+
from typing import List, NoReturn
44

55
from fastapi import status
66
from fastapi.exceptions import HTTPException
@@ -73,17 +73,12 @@ def raise_error(request: Request) -> NoReturn:
7373
)
7474

7575

76-
def extract_credentials(
77-
authorization: HTTPAuthorizationCredentials, host: str
78-
) -> List[str]:
76+
def extract_credentials(authorization: HTTPAuthorizationCredentials) -> List[str]:
7977
"""Extract the credentials from ``Authorization`` headers and decode it before returning as a list of strings.
8078
8179
Args:
8280
authorization: Authorization header from the request.
83-
host: Host header from the request.
8481
"""
85-
if not authorization:
86-
raise_error(host)
8782
decoded_auth = secure.base64_decode(authorization.credentials)
8883
# convert hex to a string
8984
auth = secure.hex_decode(decoded_auth)
@@ -95,7 +90,7 @@ def verify_login(
9590
request: Request,
9691
env_username: str,
9792
env_password: str,
98-
) -> Dict[str, Union[str, int]]:
93+
) -> str | NoReturn:
9994
"""Verifies authentication and generates session token for each user.
10095
10196
Args:
@@ -105,12 +100,13 @@ def verify_login(
105100
env_password: Environment variable for the password.
106101
107102
Returns:
108-
Dict[str, str]:
109-
Returns a dictionary with the payload required to create the session token.
103+
str:
104+
Returns the session token.
110105
"""
111-
username, signature, timestamp = extract_credentials(
112-
authorization, request.client.host
113-
)
106+
if authorization:
107+
username, signature, timestamp = extract_credentials(authorization)
108+
else:
109+
raise_error(request)
114110
if secrets.compare_digest(username, env_username):
115111
hex_user = secure.hex_encode(env_username)
116112
hex_pass = secure.hex_encode(env_password)
@@ -122,15 +118,14 @@ def verify_login(
122118
if secrets.compare_digest(signature, expected_signature):
123119
models.ws_session.invalid[request.client.host] = 0
124120
key = secrets.token_urlsafe(64)
125-
# fixme: By setting a path instead of timestamp, this can handle path specific sessions
126-
models.ws_session.client_auth[request.client.host] = dict(
127-
username=username, token=key, timestamp=int(timestamp)
128-
)
129-
return models.ws_session.client_auth[request.client.host]
121+
models.ws_session.client_auth[request.client.host] = key
122+
return key
130123
raise_error(request)
131124

132125

133-
def session_check(api_request: Request = None, api_websocket: WebSocket = None) -> None:
126+
def verify_session(
127+
api_request: Request = None, api_websocket: WebSocket = None
128+
) -> None:
134129
"""Check if the session is still valid.
135130
136131
Args:
@@ -150,9 +145,7 @@ def session_check(api_request: Request = None, api_websocket: WebSocket = None)
150145
detail="Request or WebSocket connection is required for session check.",
151146
)
152147
session_token = request.cookies.get("session_token")
153-
stored_token = models.ws_session.client_auth.get(request.client.host, {}).get(
154-
"token"
155-
)
148+
stored_token = models.ws_session.client_auth.get(request.client.host)
156149
if (
157150
stored_token
158151
and session_token

verify/fast_api.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import uvicorn
22
from fastapi import FastAPI, status
33
from fastapi.requests import Request
4-
from fastapi.responses import HTMLResponse, JSONResponse
4+
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
55
from fastapi.routing import APIRoute
66

77
import fastapiauthenticator as auth
88

99

10+
def root_page() -> RedirectResponse:
11+
"""Re-direct the user to login page."""
12+
return RedirectResponse(url="/sensitive-data", status_code=status.HTTP_302_FOUND)
13+
14+
1015
def hello_world() -> JSONResponse:
1116
"""A simple function that returns a JSON response with a greeting message."""
1217
return JSONResponse({"message": "Hello, World!"})
@@ -22,6 +27,10 @@ def secure_function(_: Request) -> HTMLResponse:
2227

2328
app = FastAPI(
2429
routes=[
30+
APIRoute(
31+
path="/",
32+
endpoint=root_page,
33+
),
2534
APIRoute(
2635
path="/hello",
2736
endpoint=hello_world,

0 commit comments

Comments
 (0)