AWS Viewer Integrations with R

Problem

You are building an interactive Python application which needs to assume an AWS IAM role in order to access a private AWS resource, like S3. The content must authenticate to an identity provider configured to be validated by AWS using the viewer’s credentials. For example, you might need to read data from an IAM-role-restricted S3 bucket.

Solution

The examples below illustrate how to use the OAuth integrations feature of Posit Connect to delegate authorization for access to an external provider’s resources. In this case, we are focusing on S3 within AWS. These examples use the viewer’s OIDC token to assume an AWS IAM role that provides temporary session credentials to the content. These credentials are used to call the AWS API on behalf of the content viewer.

Ensure you have the following dependencies installed:

  • shiny
  • connectapi
  • arrow
  • DT

When publishing the content to Connect make sure the following environment variables are set for the deployed content:

  • AWS_REGION
  • AWS_BUCKET_NAME
  • AWS_S3_FILEPATH
app.R
library(shiny)
library(connectapi)
library(arrow)
library(DT)

ui <- fluidPage(
  h2("S3 Data Viewer"),
  DTOutput("data_grid")
)

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

  # Obtain AWS credentials and start a session:
  # 1. If running on Posit Connect, perform a credential exchange with the
  #    content session token that is provided at app startup.
  # 2. If running locally, initialize a session using your preferred method.
  #    This example assumes the use of the aws cli to authenticate.
  bucket <- NULL
  bucket_name <- Sys.getenv("AWS_BUCKET_NAME")
  filepath <- Sys.getenv("AWS_S3_FILEPATH")

  # if running on Connect
  if (Sys.getenv("POSIT_PRODUCT") == "CONNECT") {
    # init Posit Connect API client
    client <- connect()
    user_session_token <- session$request$HTTP_POSIT_CONNECT_USER_SESSION_TOKEN
    credentials <- get_aws_credentials(client, user_session_token)
    bucket <- arrow::s3_bucket(bucket_name,
                               access_key = credentials$access_key_id,
                               secret_key = credentials$secret_access_key,
                               session_token = credentials$session_token
    )
  } else {
    # Use default credentials from environment/config
    bucket <- arrow::s3_bucket(bucket_name)
  }

  # Get the object from S3 and read into dataframe
  # Assumes csv file. Use other file reader functions
  # for other file types e.g. arrow::read_parquet().
  df <- arrow::read_csv_arrow(bucket$path(filepath))

  output$data_grid <- renderDT({
    df
  })
}

shinyApp(ui, server)