OAuth Integrations

Enhanced Advanced

Applications hosted on Posit Connect can be configured to use the content viewer’s OAuth access token, allowing publishers to author content that has access to third-party protected resources. This feature makes it possible for the content to user the viewer’s credentials when accessing protected resources, providing the viewer with a personalized view of the content. Access controls for protected resources are defined externally, allowing data administrators to reuse their organization’s existing data access policies and procedures. In Connect, viewers only see the data they have been granted access to in the third-party system.

Note

OAuth integrations are only supported for interactive content types. Static and rendered content do not support OAuth integrations.

Content with access type Anyone - no login required is not supported.

For more information on configuring OAuth integrations in Connect, see the OAuth Integrations section of the Admin Guide.

Authoring content

When authoring content that requires access to protected resources, publishers should use the Posit SDK or call the Connect Server API’s /v1/oauth/integrations/credentials endpoint directly to obtain the viewer’s OAuth credentials.

In order for the content to obtain the viewer’s access token, the following criteria must be met:

  • The content must be deployed to Connect.
  • The viewer must visit the running content on Connect.
  • The viewer must log in to the OAuth integration on Connect.

Obtaining a viewer OAuth access token

Connect makes the viewer’s access token available to content through the /v1/oauth/integrations/credentials endpoint, which is an implementation of an OAuth Token Exchange.

When content is running on Connect, a short-lived user-session-token is attached to the Posit-Connect-User-Session-Token HTTP header for all interactive content requests. The user-session-token serves as the subject_token in the credential exchange request.

The following examples demonstrate how to perform a credential exchange in order to obtain the viewer’s access token from Connect.

Warning

Publishers must take care to ensure that access tokens are not leaked through content logs, cached incorrectly by the content, or otherwise misused. Each Python and R web application framework exposes session/application state differently. It is up to the publisher to understand in which context it is appropriate to request and use a viewer’s access token.

Note

This example uses the Shiny for Python web application framework and the posit-python-sdk to perform the credential exchange.

from posit import connect
from shiny.express import render, session

# initialize the Connect client
# runs once per startup
client = connect.Client()

# runs once per session
@render.text
def access_token():
    # read the user-session-token header
    user_session_token = session.http_conn.headers.get("Posit-Connect-User-Session-Token")

    # fetch the viewer's access token
    return client.oauth.get_credentials(user_session_token).get("access_token")
Note

This example uses the Shiny for R web application framework and the connectapi package to perform the credential exchange.

library(connectapi)
library(shiny)

ui <- fluidPage(textOutput("access_token"))

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

  # initialize the Connect client
  client <- connect()

  # read the user-session-token header
  user_session_token <- session$request$HTTP_POSIT_CONNECT_USER_SESSION_TOKEN

  output$access_token <- renderText({
    # fetch the viewer's access token
    credentials <- get_oauth_credentials(client, user_session_token)
    credentials$access_token
  })
}

# start the Shiny app
shinyApp(ui = ui, server = server)

Local development

OAuth integrations can only be used to obtain the viewer’s access token when the content is running on a Connect server, so testing local changes to content can be challenging. A good strategy for authoring content that uses OAuth integrations is to first check whether the content is running on a Connect server, and then fall-back to the user’s locally configured credentials when it is not. All content running on a Connect server has the following environment variable set: RSTUDIO_PRODUCT=CONNECT. This environment variable can be used by the content to determine if it is running on a Connect server.

See the sample code in the Posit SDK for Python for examples of how to use the Databricks OAuth integration from various Python application frameworks. The Posit SDK for Python and the equivalent connectapi R package are under active development and contributions are welcome.

Access token refresh

Access tokens are short-lived, usually expiring within 24 hours of when they were issued. Content that utilizes access tokens must be resilient to errors that can occur when the access token expires. To simplify this for content authors, Connect is responsible for access token refresh. Requesting a viewer’s access token from the /v1/oauth/integrations/credentials endpoint always returns a refreshed access token.

Connect encrypts and stores the viewer’s access token and refresh token with their OAuth session. If the viewer’s access token is valid, it is returned right away. If the viewer’s access token is expired (or about to expire) then Connect will attempt to refresh the OAuth Access Token first, before returning it to the requester (the content). OAuth refresh tokens are never returned by Connect.

Adding OAuth integrations to deployed content

Once the content has been deployed to Connect, the publisher associates the OAuth integration with their content.

This is accomplished using the dashboard by visiting the Access tab in the Content Settings pane, where the publisher will see an Integrations section with an Add integration button.

The Access tab provides an Add integration button.

Clicking this button will open a modal which allows the Connect publisher to select an OAuth integration.

Example of publisher OAuth integration selection.

After selecting an integration and saving, the Add integration button is replaced with a panel containing information about the integration and a button to log in to the OAuth Integration.

Completed OAuth integration selection.

Alternatively, the example below uses curl and the Connect Server API to associate an OAuth integration with an existing piece of deployed content in Connect.

Note

Replace connect.example.org with the address of the Connect server.

Terminal
# list all available oauth integrations
curl -H "Authorization: Key ${CONNECT_API_KEY}" \
  -XGET https://connect.example.org/__api__/v1/oauth/integrations

# assign an oauth integration to a piece of content
curl -H "Authorization: Key ${CONNECT_API_KEY}" \
  -XPUT https://connect.example.org/__api__/v1/content/<content-guid>/oauth/integrations/associations \
  --data '[
    {"oauth_integration_guid": "<oauth-integration-guid>"}
  ]'

Viewing content on Connect

Connect users who have the Viewer permission on the content item receive a personalized view when they visit the deployed application.

OAuth integration viewer impersonation in Posit Connect.

Upon visiting a piece of content that is associated with an OAuth integration for the first time, if the user is accessing the content through the Connect dashboard, they are prompted to login to the OAuth integration.

Note

The login modal only appears if the user is not already logged in and the content settings pane is closed. The Login button is also available on the Access tab of the Content Settings pane.

The Login modal displayed on the viewer's first visit to the content.

When interacting with the content in open-solo mode and the viewer is not already logged in, then the viewer is automatically redirected to the login URL of the OAuth integration in order to initialize their OAuth session.

OAuth sessions

An OAuth session holds metadata about the Connect user’s OAuth tokens. An OAuth session is created when a Connect user visits the /login endpoint of any OAuth integration. The login endpoint has the form: /__oauth__/integrations/<oauth-integration-guid>/login. In order to populate the OAuth session with an access token and refresh token, the user must complete the login flow by visiting the /login endpoint and successfully authenticating to the external service. After authenticating to the external service, the user is redirected back to Connect.

The user’s OAuth session and all OAuth tokens are deleted when the Connect user visits the /logout endpoint. The logout endpoint has the form: /__oauth__/integrations/<oauth-integration-guid>/logout.

Note

OAuth sessions can also be managed using the /v1/oauth/sessions API endpoints. By default, Connect users can only manage their own OAuth sessions. Connect administrators can manage OAuth sessions of all Connect users. Managing an OAuth session does not allow the user to view OAuth tokens associated with the OAuth session. Access tokens are exposed only by the credential exchange endpoint. OAuth refresh tokens are never returned by Connect.

An authenticated user in Connect can have only one OAuth session per OAuth integration. A given OAuth integration can be shared by multiple content items on Connect. The user only needs to login to the OAuth integration once and the OAuth session remains valid for all pieces of content that use that OAuth integration. A user is considered to be logged in to the OAuth integration if there is an OAuth refresh token associated with the OAuth session.

Note

A content viewer must visit a piece of content in order for the content to obtain the viewer’s access token. Simply associating an OAuth integration with a piece of content is not enough for the content to obtain the user’s access token.

This limitation prevents a content item from obtaining an arbitrary user’s access token, even when that user is assigned the Viewer role on the content. See the security documentation for additional details.