MS Graph endpoint validation with Python

Problem

Your Posit Connect administrator has informed you that the Microsoft Graph OAuth integration has been configured and can now be added to content. When asked what endpoints are accessible via the integration the Connect administrator is not sure, as the Microsoft Entra administator set up the application on the Microsoft side.

Solution

In order to verify the endpoints available to the integration you create a basic Streamlit application that:

  • Checks for an access token and prompts the user to either login or supply the token via an environment variable.

  • Makes a request to the /me MS Graph endpoint to retrieve user information and greet the user, displaying an error on failure.

  • Prompts the user for an endpoint to request.

  • Requests the endpoint when the user submits one, either displaying the results in JSON or returning an error on failure.

requirements.txt
streamlit
posit-sdk==0.5.0
app.py
# -*- coding: utf-8 -*-
# mypy: ignore-errors

import os
import requests
import streamlit as st
from posit import connect

# initialize the Connect python sdk client if running on Connect
if os.getenv("RSTUDIO_PRODUCT") == "CONNECT":
    client = connect.Client()

    # grab the user session token from headers
    user_session_token = st.context.headers.get("Posit-Connect-User-Session-Token")

    try:
        # fetch the access token using the session token
        access_token = client.oauth.get_credentials(user_session_token).get(
            "access_token"
        )
    # if the refresh token has expired prompt the user to login again
    except connect.errors.ClientError as e:
        if e.error_code == 219:
            st.write(
                "Your MS Graph refresh token has expired. Please log out and log in to the integration."
            )
else:
    # grab access token from env var if running locally
    access_token = os.getenv("MSGRAPH_TOKEN")

try:
    # check for the existence of the access_token to prevent failures later
    if not access_token:
        print("Checking for access token.")

    # only request the /me endpoint if we have an access token
    if access_token:

        # set authorization and accept headers
        headers = {
            "Authorization": f"Bearer {access_token}",
            "Accept": "application/json;odata.metadata=full;odata.streaming=true",
        }

        # make the request to /me
        url = "https://graph.microsoft.com/v1.0/me"
        response = requests.get(url, headers=headers)

        # check that the request was successful and greet the user if so
        if response.status_code == 200:
            resp_json = response.json()
            name = resp_json["displayName"]
            st.write(f"Greetings, {name}!")

            # prompt the user for an endpoint to request
            endpoint = st.text_input(
                "Enter an MS Graph endpoint to request it: ", placeholder="/me/manager"
            )
            if endpoint:
                url = f"https://graph.microsoft.com/v1.0{endpoint}"
                response = requests.get(url, headers=headers)
                # check for success
                if response.status_code == 200:
                    resp_json = response.json()
                    st.write(f"Your query to {url} returned: ", resp_json)
                # error on failure
                else:
                    st.write(
                        f"An error occurred while querying {url}: ",
                        response.status_code,
                        response.text,
                    )
        # output error on failure
        else:
            st.write("User query failed: ", response.status_code, response.text)

except NameError:
    st.write("Unable to obtain access token.")
    # depending on environment prompt the user to log in or pass the env var
    if os.getenv("RSTUDIO_PRODUCT") == "CONNECT":
        st.write("Are you logged into the OAuth integration?")
    else:
        st.write("Is the MSGRAPH_TOKEN env var set?")

Running the app locally

Terminal
export CONNECT_SERVER=<connect-server>
export CONNECT_API_KEY=<connect-api-key>
MSGRAPH_TOKEN=<msgraph-token> streamlit run app.py