Spaces:
Running
Running
import os | |
import streamlit as st | |
import requests | |
import msal | |
import base64 | |
import hashlib | |
import secrets | |
# π€ Load environment variables (Ensure these are set!) | |
APPLICATION_ID_KEY = os.getenv('APPLICATION_ID_KEY') | |
CLIENT_SECRET_KEY = os.getenv('CLIENT_SECRET_KEY') | |
AUTHORITY_URL = 'https://login.microsoftonline.com/common' # Use 'common' for multi-tenant apps | |
REDIRECT_URI = 'https://huggingface.co/spaces/awacke1/MSGraphAPI' # Update this to match your app's redirect URI | |
# π― Define the scopes your app will need | |
SCOPES = ['User.Read'] | |
# New function to generate PKCE code verifier and challenge | |
def generate_pkce_codes(): | |
code_verifier = secrets.token_urlsafe(128)[:128] | |
code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode()).digest()).decode().rstrip('=') | |
return code_verifier, code_challenge | |
# π οΈ Initialize the MSAL client for Public Client App (PKCE support) | |
def get_msal_app(): | |
return msal.PublicClientApplication( | |
client_id=APPLICATION_ID_KEY, | |
authority=AUTHORITY_URL | |
) | |
# π Acquire access token using authorization code | |
def get_access_token(code, code_verifier=None): | |
client_instance = get_msal_app() | |
st.write("Debug: MSAL App Configuration:") | |
st.write(f"Client ID: {APPLICATION_ID_KEY[:5]}...") | |
st.write(f"Authority: {AUTHORITY_URL}") | |
st.write(f"Redirect URI: {REDIRECT_URI}") | |
try: | |
# Attempt to acquire token, use PKCE code_verifier if provided | |
result = client_instance.acquire_token_by_authorization_code( | |
code=code, | |
scopes=SCOPES, | |
redirect_uri=REDIRECT_URI, | |
code_verifier=code_verifier # Include only if PKCE is enabled | |
) | |
if 'access_token' in result: | |
return result['access_token'] | |
else: | |
error_description = result.get('error_description', 'No error description provided') | |
raise Exception(f"Error acquiring token: {error_description}") | |
except Exception as e: | |
st.error(f"Exception in get_access_token: {str(e)}") | |
raise | |
# πββοΈ Main function to process the query parameters and handle the token exchange | |
def process_query_params(): | |
try: | |
query_params = st.experimental_get_query_params() | |
st.write("Debug: All query parameters:", query_params) | |
if 'error' in query_params: | |
error = query_params.get('error') | |
error_description = query_params.get('error_description', 'No description provided') | |
st.error(f"Authentication Error: {error}") | |
st.error(f"Error Description: {error_description}") | |
st.stop() | |
if 'code' in query_params: | |
code = query_params.get('code')[0] # MS Graph returns the code as a list | |
st.write('π Authorization Code Obtained:', code[:10] + '...') | |
try: | |
# Retrieve code_verifier from session state | |
code_verifier = st.session_state.get('code_verifier') | |
if not code_verifier: | |
st.error("Code verifier not found in session state.") | |
st.stop() | |
# Acquire the access token | |
access_token = get_access_token(code, code_verifier) | |
st.session_state['access_token'] = access_token | |
st.success("Access token acquired successfully!") | |
# Clear the query parameters from the URL | |
st.experimental_set_query_params() | |
st.experimental_rerun() | |
except Exception as e: | |
st.error(f"Error acquiring access token: {str(e)}") | |
st.stop() | |
else: | |
st.warning("No authorization code found in the query parameters.") | |
except Exception as e: | |
st.error(f"Error processing query parameters: {str(e)}") | |
st.stop() | |
# Main application function | |
def main(): | |
st.title("π¦ MS Graph API with AI & Cloud Integration with M365") | |
if 'access_token' not in st.session_state: | |
if 'code_verifier' not in st.session_state: | |
# Generate PKCE codes and store code_verifier in session | |
code_verifier, code_challenge = generate_pkce_codes() | |
st.session_state['code_verifier'] = code_verifier | |
else: | |
code_verifier = st.session_state['code_verifier'] | |
code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode()).digest()).decode().rstrip('=') | |
# Get MSAL app and construct the authorization URL | |
client_instance = get_msal_app() | |
auth_url = client_instance.get_authorization_request_url( | |
scopes=SCOPES, | |
redirect_uri=REDIRECT_URI, | |
code_challenge=code_challenge, | |
code_challenge_method="S256" | |
) | |
st.write('π Please [click here]({}) to log in and authorize the app.'.format(auth_url)) | |
st.stop() | |
# Process query parameters to acquire token | |
process_query_params() | |
# If access token is present, greet the user | |
if 'access_token' in st.session_state: | |
access_token = st.session_state['access_token'] | |
headers = {'Authorization': 'Bearer ' + access_token} | |
response = requests.get('https://graph.microsoft.com/v1.0/me', headers=headers) | |
if response.status_code == 200: | |
user_info = response.json() | |
st.write(f"π Hello, {user_info['displayName']}!") | |
else: | |
st.error("Failed to fetch user info.") | |
st.write(response.text) | |
# π Run the main function | |
if __name__ == "__main__": | |
main() | |