File size: 5,673 Bytes
921344f
 
 
 
a13b66a
 
921344f
 
a13b66a
 
 
 
 
921344f
a13b66a
 
921344f
a13b66a
 
 
 
 
ec81794
a13b66a
 
 
 
 
b513742
 
a13b66a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ec81794
a13b66a
 
 
 
 
ec81794
a13b66a
 
 
 
 
 
a81cb6d
a13b66a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a78ffeb
a13b66a
 
 
b513742
a13b66a
 
 
 
 
 
 
 
b513742
a13b66a
 
 
 
 
 
 
 
 
 
921344f
a13b66a
 
b513742
a13b66a
 
 
 
b513742
a13b66a
 
 
 
 
 
 
921344f
a13b66a
921344f
a13b66a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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()