I’m working on a sign in system for Azure AD. I’ve gotten to the point where Microsoft is returning a code and state in the url so I can then take that and do stuff. I’ve set up a dynamic route to catch what they send me. The problem is that their URL variable starts with a #. This stop dynamic routing for anything after the #, which is everything in this case as in the example below. I can’t even use a str.replace() because it treats everything after the # as commented out. If you copy and run the example below, you can move the # to anywhere in the dynamic portion of the URL and it will show everything up to that point. Is there anything that can be done to fix this?
Hey @alek ,
I’ve since learned that is the fragment method and switched over to trying the query response mode instead. I’m still running into an issue where the incoming query from Microsoft is empty. I’ve found the rx.state.router.page.params and thought it would be in there, but there isn’t anything in there. Here’s the current code I’m testing below. It doesn’t get past the auth_state check in the handle_callback function. Should the page.params be where I’m looking? Is there another place or a setting I’m missing?
class State(rx.State):
authenticated_user: bool = False
user_info: str = ""
session_state: str = "" # Store the session state for comparison
auth_session: dict = None # Store auth session details
def handle_login(self):
# Generate a unique session state to track the request
self.session_state = ''.join(random.choices(string.ascii_letters, k=16))
# Start the auth code flow and store the session
self.auth_session = msal_app.initiate_auth_code_flow(
scopes=msal_config["scope"],
redirect_uri=msal_config["redirect_uri"], # Do not modify this
state=self.session_state
)
if self.auth_session and 'auth_uri' in self.auth_session:
auth_url = self.auth_session['auth_uri']
return rx.redirect(auth_url)
else:
print("Error initiating auth code flow.")
self.user_info = "Error during login initiation."
def handle_callback(self):
# Retrieve authorization response from Reflex's router page parameters
auth_response = self.router.page.params
# Compare session state from URL with the one stored in the state
if self.session_state != auth_response.get('state'):
print(f"State mismatch: {self.session_state} vs {auth_response.get('state')}")
self.user_info = "Authentication failed due to state mismatch."
self.authenticated_user = False
return
if not self.auth_session:
print("Auth session not found or expired.")
self.user_info = "Session expired or invalid request."
self.authenticated_user = False
return
try:
# Use MSAL to exchange the auth code for tokens
result = msal_app.acquire_token_by_auth_code_flow(self.auth_session, auth_response)
if "access_token" in result:
self.user_info = "Authenticated successfully"
self.authenticated_user = True
else:
error = result.get("error", "Unknown error")
print(f"Error in token acquisition: {error}")
self.user_info = f"Authentication failed: {error}"
self.authenticated_user = False
except ValueError as e:
print(f"Error during authentication: {e}")
self.user_info = "Authentication failed due to CSRF error"
self.authenticated_user = False
def index():
return rx.container(
rx.button("Login with Microsoft", on_click=State.handle_login),
)
def callback_page():
return rx.container(
rx.checkbox(checked=State.authenticated_user),
rx.text(State.user_info),
rx.text_area(str(State.router.page.params)), # Display query params for debugging
)
app = rx.App()
app.add_page(callback_page, "/callback", on_load=State.handle_callback)
app.add_page(index, "/")