OAuth Integrations Security

Enhanced Advanced

This section provides additional details about the Posit Connect OAuth integrations feature, with a particular focus on the security implications of its design and operation.

OAuth integrations

Setting up an OAuth integration may require configuring sensitive fields, such as an OAuth client secret for integrations which target confidential OAuth clients. Sensitive fields are encrypted-at-rest in the Connect database and are never returned by the Connect Server API.

OAuth integrations in Connect use the PKCE (Proof Key for Code Exchange) extension for the authorization code flow by default. PKCE is required in the upcoming OAuth 2.1 specification, and is recommended in all cases to protect against authorization code injection attacks. If necessary, PKCE can be disabled by creating a Custom integration, but this is not recommended.

Publishers must explicitly opt-in to use a particular OAuth integration with their content, either through the Access tab in the Content Settings pane or through the Connect Server API. Content may only request OAuth access tokens for an integration with which it has been explicitly associated. Content never has access to sensitive information about configured OAuth integrations.

OAuth integrations are not supported for content which uses the Anyone - no login required access type. This means that every OAuth token maintained by Connect is linked to a named user on the server. 

Modifying integrations

Connect allows OAuth integration edits to support certain essential maintenance and upkeep operations such as secret rotation. Given that there are certain contexts where edits to OAuth integrations are necessary, an OAuth integration should not be modified to point to an entirely different authentication provider. This implicit restriction ensures that access tokens from active user sessions are not leaked to an unintended authentication provider.

Viewer identity delegation

At its core, the OAuth Integration feature in Connect enables viewer identity delegation. When a viewer is directed to log in to a third-party OAuth application by Connect, the viewer’s identity, represented by an OAuth access token, is stored and maintained on the Connect server. Under specific, well-defined circumstances, executing content is able to request this access token from Connect on behalf of the viewer.

In brief, the restrictions around when and how this credential exchange can occur ensure that both the user requesting the credential exchange and the viewer have the correct permissions, and that the viewer has recently interacted with the content which is requesting their OAuth access token. Additional details about the behavior of this credential exchange operation are provided below.

Once the executing content acquires the viewer’s OAuth access token, it can then make authenticated requests to a third-party protected resource using the viewer’s token.

Note

OAuth access tokens are short-lived credentials which expire. Additional details about the security implications of publishers’ control over OAuth credentials are provided below.

Credential exchange

The Connect Server API endpoint which provides the OAuth access token to requesting content implements RFC8693. This token exchange service specification lays out strict semantics for interacting with this endpoint and facilitates well-defined interactions that must meet certain security-related criteria to succeed.

Request

Following RFC8693, a valid request to the credential exchange endpoint must include a valid subject_token. This token must have a subject_token_type of urn:posit:connect:user-session-token.

A urn:posit:connect:user-session-token is a signed Json Web Token (JWT) with the following claims:

User Session Token Claims
Name Description
Iss Address of the Connect server that issued the subject_token.
Sub GUID identifying the content viewer.
Job Identifies the underlying content process for which the subject token can be used.
App App ID of the accessed content. Connect uses this value to verify that both the authenticated user who is requesting a viewer’s OAuth access token and the content viewer have permission to receive the OAuth access token.
Iat Unix timestamp indicating when the subject_token was issued by the Connect server.
Exp Unix timestamp indicating when the subject_token expires. Connect sets the expiration to be 24 hours from the time the token was issued.

When a subject_token is created, Connect signs it using an ephemeral secret. This secret’s life cycle is coupled to the life cycle of the executing content process.

The subject_token’s design produces the following properties which help to prevent misuse:

  • The viewer must have recently interacted with the content which is requesting their OAuth access token.

  • The user requesting the token exchange must have owner permissions on the content item.

  • The viewer must have permission to view the content item.

  • The subject_token must have been issued by the server that is receiving the credential request.

  • The subject_token must have been produced within the past 24 hours.

Response

  • The credential exchange only returns an OAuth access token. Connect never exposes refresh tokens externally. 

  • Connect must have received a viewer’s OAuth credentials before the credential exchange occurs. This means that:

    • The content being accessed by the viewer must have been explicitly associated with an OAuth integration by the content publisher.

    • The viewer must have already logged into the OAuth provider and delegated their OAuth credentials to Connect before the credential exchange is initiated.

Publisher trust model

When deployed content requests an OAuth access token from Connect, by definition, the content receives a credential which provides it with the ability to access private external resources that are owned by the viewer. Once the content receives this credential, Connect cannot control its use. Connect implicitly trusts that publishers’ content will not misuse delegated credentials, either maliciously or unintentionally.

Note

Published content only receives OAuth access tokens, which are short-lived credentials designed to eventually expire.

This trust model, which assumes that publishers will not misuse or abuse system assets, exists elsewhere in Connect. For example, this same implicit trust relationship applies to content that executes using Current User Execution accessing privileged resources. This is not a change in the fundamental trust model between the server and deployed content. Rather, it is an extension of the same underlying trust model with the following additional implications:

  • Publishers should take care to ensure that OAuth access tokens are not unintentionally leaked through content logs, cached outside of the content process, or otherwise observed external to the executing content. 

  • Administrators should regularly audit user roles to ensure that users with the Publisher role are trusted actors on the server. 

Encryption

Stored credentials

All OAuth credentials stored by Connect are encrypted-at-rest.

Network traffic

When considering the network topology of Connect, and by implication, the relevant network boundaries over which sensitive data might be communicated, it is useful to consider local and off-host execution separately.

Note

The following discussion assumes Connect has been configured to use SSL/TLS. It also assumes the third-party protected resource is configured to use SSL/TLS. Communication with third-party resource(s) is out-of-scope for this document.

Local execution

In the network diagram below, a user initiates communication with Connect which targets some interactive content process, either over HTTPS or websockets using SSL (WSS) (1). Connect then proxies this request to the content (2). Finally, the content initiates a credential exchange request on behalf of the user (3) in order to acquire an OAuth access token which can be used to communicate with some third-party protected resource.

When Connect is running in local execution, all communication which crosses a network boundary (1 and 3) is encrypted by TLS. In particular, note that the credential exchange (3) uses the public Connect Server API to securely communicate the OAuth access token to the requesting content.

Network boundary diagram for local execution

Local execution network topology
Off-host execution

The network topology of the off-host execution model on Connect is very similar to local execution. The initiating communication between a user and Connect remains unchanged (1). The token exchange which serves an OAuth access token to executing content still occurs over the TLS-backed Connect Server API (3). However, communication between the Connect server and the interactive content it manages now crosses an intra-cluster network boundary, because communication must pass between Kubernetes pods (2).

Network boundary diagram for off-host execution

Off-host execution network topology

Traffic between the Connect server and executing content in Kubernetes (2) is not encrypted.

This network boundary is not encrypted for the following reasons:

  • Connect assumes that intra-network communication is managed by Kubernetes administrators who have hardened the external boundaries of the cluster against malicious actors.

  • Best practices dictate that communication within a Kubernetes cluster should be holistically secured by installing a service mesh.

Importantly, OAuth credentials are not communicated directly to executing content across this intra-cluster network boundary. The only relevant data that crosses this network boundary is the signed subject_token, which content can subsequently use to initiate a credential exchange through the TLS-secured Connect Server API to receive an OAuth access token.

No sensitive information is communicated in the subject_token. The signing secret used to verify the integrity of the user session token never crosses any network boundaries.

Process management

While each client session will use a user subject token which is scoped uniquely to the viewer, multiple clients which connect to the same application may reuse the same underlying Python or R process. Because of this, published application code must be careful to scope sensitive information to the lifecycle of the client session. For example, applications should not store sensitive information in global variables which persist outside of the client session and are instead tied to the lifecycle of the Python or R process.

Connect’s application process management documentation provides additional information about how Connect manages long-running processes to service client connections.