Skip to content

Commit 6f5e5cb

Browse files
fix(router): allow forward all request query params on login and filter sensitive ones (#16)
1 parent f319f6b commit 6f5e5cb

File tree

3 files changed

+304
-259
lines changed

3 files changed

+304
-259
lines changed

packages/auth0_fastapi/src/auth0_fastapi/auth/auth_client.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,36 @@
66

77
from auth0_fastapi.config import Auth0Config
88

9-
#Imported from auth0-server-python
9+
# Imported from auth0-server-python
1010
from auth0_server_python.auth_server.server_client import ServerClient
1111
from auth0_server_python.auth_types import (
1212
StartInteractiveLoginOptions,
1313
LogoutOptions
1414
)
1515

16+
1617
class AuthClient:
1718
"""
1819
FastAPI SDK client that wraps auth0-server-python functionality.
1920
It configures the underlying client with the proper state and transaction stores,
2021
and exposes helper methods for starting login, completing the login callback,
2122
logging out, and handling backchannel logout.
2223
"""
24+
2325
def __init__(self, config: Auth0Config, state_store=None, transaction_store=None):
2426
self.config = config
2527
# Build the redirect URI based on the provided app_base_url
26-
redirect_uri = f"{str(config.app_base_url).rstrip('/')}/auth/callback"
27-
28+
redirect_uri = f"{str(config.app_base_url).rstrip('/')}/auth/callback"
29+
2830
# Use provided state_store or default to cookie implementation
2931
if state_store is None:
30-
state_store = StatelessStateStore(config.secret, cookie_name="_a0_session", expiration=config.session_expiration)
32+
state_store = StatelessStateStore(
33+
config.secret, cookie_name="_a0_session", expiration=config.session_expiration)
3134
# Use provided transaction_store or default to an cookie implementation
3235
if transaction_store is None:
33-
transaction_store = CookieTransactionStore(config.secret, cookie_name="_a0_tx")
34-
36+
transaction_store = CookieTransactionStore(
37+
config.secret, cookie_name="_a0_tx")
38+
3539
self.client = ServerClient(
3640
domain=config.domain,
3741
client_id=config.client_id,
@@ -47,37 +51,41 @@ def __init__(self, config: Auth0Config, state_store=None, transaction_store=None
4751
**(config.authorization_params or {})
4852
},
4953
)
50-
51-
async def start_login(self, app_state: dict = None, store_options: dict = None) -> str:
54+
55+
async def start_login(self, app_state: dict = None, authorization_params: dict = None, store_options: dict = None) -> str:
5256
"""
5357
Initiates the interactive login process.
5458
Optionally, an app_state dictionary can be passed to persist additional state.
5559
Returns the authorization URL to redirect the user.
5660
"""
57-
options = StartInteractiveLoginOptions(app_state=app_state)
61+
pushed_authorization_requests = self.config.pushed_authorization_requests
62+
options = StartInteractiveLoginOptions(
63+
pushed_authorization_requests=pushed_authorization_requests,
64+
app_state=app_state,
65+
authorization_params=authorization_params if not pushed_authorization_requests else None
66+
)
5867
return await self.client.start_interactive_login(options, store_options=store_options)
59-
68+
6069
async def complete_login(self, callback_url: str, store_options: dict = None) -> dict:
6170
"""
6271
Completes the interactive login process using the callback URL.
6372
Returns a dictionary with the session state data.
6473
"""
6574
return await self.client.complete_interactive_login(callback_url, store_options=store_options)
66-
67-
async def logout(self, return_to: str = None, store_options: dict = None ) -> str:
75+
76+
async def logout(self, return_to: str = None, store_options: dict = None) -> str:
6877
"""
6978
Initiates logout by clearing the session and generating a logout URL.
7079
Optionally accepts a return_to URL for redirection after logout.
7180
"""
7281
options = LogoutOptions(return_to=return_to)
7382
return await self.client.logout(options, store_options=store_options)
74-
83+
7584
async def handle_backchannel_logout(self, logout_token: str) -> None:
7685
"""
7786
Processes a backchannel logout using the provided logout token.
7887
"""
7988
return await self.client.handle_backchannel_logout(logout_token)
80-
8189

8290
async def start_link_user(self, options: dict, store_options: dict = None) -> str:
8391
"""
@@ -90,15 +98,15 @@ async def start_link_user(self, options: dict, store_options: dict = None) -> st
9098
Returns a URL to redirect the user to for linking.
9199
"""
92100
return await self.client.start_link_user(options, store_options=store_options)
93-
101+
94102
async def complete_link_user(self, url: str, store_options: dict = None) -> dict:
95103
"""
96104
Completes the user linking process.
97105
The provided URL should be the callback URL from Auth0.
98106
Returns a dictionary containing the original appState.
99107
"""
100108
return await self.client.complete_link_user(url, store_options=store_options)
101-
109+
102110
async def start_unlink_user(self, options: dict, store_options: dict = None) -> str:
103111
"""
104112
Initiates the user unlinking process.
@@ -109,15 +117,15 @@ async def start_unlink_user(self, options: dict, store_options: dict = None) ->
109117
Returns a URL to redirect the user to for unlinking.
110118
"""
111119
return await self.client.start_unlink_user(options, store_options=store_options)
112-
120+
113121
async def complete_unlink_user(self, url: str, store_options: dict = None) -> dict:
114122
"""
115123
Completes the user unlinking process.
116124
The provided URL should be the callback URL from Auth0.
117125
Returns a dictionary containing the original appState.
118126
"""
119127
return await self.client.complete_unlink_user(url, store_options=store_options)
120-
128+
121129
async def require_session(self, request: Request, response: Response) -> dict:
122130
"""
123131
Dependency method to ensure a session exists.
@@ -127,5 +135,6 @@ async def require_session(self, request: Request, response: Response) -> dict:
127135
store_options = {"request": request, "response": response}
128136
session = await self.client.get_session(store_options=store_options)
129137
if not session:
130-
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Please log in")
138+
raise HTTPException(
139+
status_code=status.HTTP_401_UNAUTHORIZED, detail="Please log in")
131140
return session

packages/auth0_fastapi/src/auth0_fastapi/server/routes.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
from ..util import to_safe_redirect, create_route_url, merge_set_cookie_headers
2+
from ..util import to_safe_redirect, create_route_url
13
from fastapi import APIRouter, Request, Response, HTTPException, Depends, Query
24
from fastapi.responses import RedirectResponse
35
from typing import Optional
46
from ..auth.auth_client import AuthClient
57
from ..config import Auth0Config
6-
from ..util import to_safe_redirect, create_route_url
78

89
router = APIRouter()
910

@@ -34,8 +35,11 @@ async def login(request: Request, response: Response, auth_client: AuthClient =
3435
"""
3536

3637
return_to: Optional[str] = request.query_params.get("returnTo")
38+
authorization_params = {k: v for k, v in request.query_params.items() if k not in [
39+
"returnTo"]}
3740
auth_url = await auth_client.start_login(
3841
app_state={"returnTo": return_to} if return_to else None,
42+
authorization_params=authorization_params,
3943
store_options={"response": response}
4044
)
4145

0 commit comments

Comments
 (0)