MS Graph endpoint validation with R

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 Shiny application that takes in an endpoint and queries it on submit, returning the results to the user on success and displaying an error otherwise.

app.R
library(shiny)
library(httr2)
library(bslib)
library(connectapi)

ui <- page_sidebar(
  title = "Microsoft Graph Endpoint Requester",
  sidebar = sidebar(
    title = "Endpoint to request",
    textInput("endpoint", "MS Graph Endpoint", placeholder = "/me/manager", value = Sys.getenv("GRAPH_ENDPOINT")),
    actionButton("submit", "Submit")
    ),
  layout_columns(
    card(
      card_header("Results"),
      verbatimTextOutput("results")
    )
  )
)

server <- function(input, output, session) {

  # check if running on Posit Connect
  if (Sys.getenv("RSTUDIO_PRODUCT") == "CONNECT") {
    # initialize Connect API client
    client <- connect()
    # read the user-session-token header
    user_session_token <- session$request$HTTP_POSIT_CONNECT_USER_SESSION_TOKEN
    # grab the OAuth Integration access token using the session token
    credentials <- get_oauth_credentials(client, user_session_token)
    token <- credentials$access_token
  } else {
    # grab the access token from the MSGRAPH_TOKEN env var if running locally
    token <- Sys.getenv("MSGRAPH_TOKEN")
  }
  
  # only request when the submit button is selected
  observeEvent(input$submit, {
    # do not allow an empty value for the graph endpoint 
    req(input$endpoint)
    # form the requested endpoint
    path <- paste0("https://graph.microsoft.com/v1.0", input$endpoint)
    # request the endpoint
    resp <- httr2::request(path) |>
      httr2::req_headers("Accept" = "application/json;odata.metadata=full;odata.streaming=true") |>
      httr2::req_auth_bearer_token(token) |>
      # to avoid HTTP response error codes being surfaced as R errors
      httr2::req_error(is_error = ~FALSE) |>
      httr2::req_perform() 
    # check the HTTP response code
    http_code <- httr2::resp_status(resp)
    if (http_code == 200) {
      # format response body now that we have the HTTP status code
      resp <- httr2::resp_body_json(resp)
      # output the response
      output$results <- renderText({
        # paste to avoid "cannot be handled by cat()" error
        paste0(resp, sep = "\n")
      })}
    # output the unexpected HTTP code
    if (http_code != 200) {
    output$results <- renderText({
      error <- paste0("Received non-200 HTTP response code: ", http_code)
      error
    })}
  })
}


shinyApp(ui, server)

Running the app locally

Terminal
Sys.setenv(CONNECT_SERVER = "<connect-host>")
Sys.setenv(CONNECT_API_KEY = "<connect-api-key>")
# MSGRAPH_TOKEN is only required when running the example locally
Sys.setenv(MSGRAPH_TOKEN = "<msgraph-token>")
shiny::runApp()