Visitor Information

Application authors can determine a unique identifier for each Connect Cloud user visiting their content, and the email address that user signed in with.

Note
  • User information is only available inside content that has been configured for private sharing, such as sharing within an organization.
  • This technique can be used in dynamic application content types, but not in documents.

The Posit-Connect-User-Session-Token http request header is provided by Connect Cloud on all requests, subject to the above limitations. The header is a standard JWT whose sub claim is a unique identifier of the Connect Cloud user making the request.

Reading the session token

This example uses PyJWT in a Shiny for Python application.

import jwt

def user_id():
    token = session.http_conn.headers.get("posit-connect-user-session-token")
    if not token:
        return "No user session token present."
    try:
        claims = jwt.decode(token, options={"verify_signature": False})
        return f"User ID (sub): {claims.get('sub', '(sub claim not found)')}"
    except Exception as e:
        return f"Failed to decode token: {e}"

This example uses jsonlite and base64enc in a Shiny for R application.

# Decodes the payload of a JWT without verifying its signature.
decode_jwt_payload <- function(token) {
  parts <- strsplit(token, ".", fixed = TRUE)[[1]]
  if (length(parts) < 2) stop("Invalid JWT: expected at least 2 segments")
  b64 <- parts[2]
  b64 <- gsub("-", "+", b64, fixed = TRUE)
  b64 <- gsub("_", "/", b64, fixed = TRUE)
  padding <- (4 - nchar(b64) %% 4) %% 4
  b64 <- paste0(b64, strrep("=", padding))
  jsonlite::fromJSON(rawToChar(base64enc::base64decode(b64)))
}

token <- session$request$HTTP_POSIT_CONNECT_USER_SESSION_TOKEN
jwt <- decode_jwt_payload(token)
user <- jwt$sub

JWT Signature verification

On privately shared content, this header’s contents are guaranteed by Connect Cloud to accurately represent the user making the request. There is no need to perform verification of the JWT’s signature.

Visitor email address

Connect Cloud also provides the email address the visitor signed in with, in a credentials request header. Shiny applications coming from shinyapps.io can read the visitor’s identity the same way they do there, through session$user.

The header name depends on the content type:

  • Shiny-Server-Credentials for Shiny applications, both Shiny for R and Shiny for Python.
  • RStudio-Connect-Credentials for the other application types: Streamlit, Dash, and Bokeh.

Its value is a JSON object:

{"user":"visitor@example.com","groups":[]}

The user field is the visitor’s email address. Connect Cloud has no group concept for content visitors, so groups is always an empty list; it is present because the frameworks that consume this header expect it.

Note

Connect Cloud discards any credentials header supplied by the visitor’s browser and sets the value itself, so your application can trust the value it receives.

Reading the credentials header

This example uses the standard library json module in a Shiny for Python application.

import json

def user_email():
    credentials = session.http_conn.headers.get("shiny-server-credentials")
    if not credentials:
        return "No visitor credentials present."
    return json.loads(credentials).get("user", "(user field not found)")

Streamlit, Dash, and Bokeh applications read the rstudio-connect-credentials header instead, through whichever request-headers API their framework provides.

Shiny for R is the only R application type on Connect Cloud, and Shiny parses the credentials header for you, exposing the email address as session$user.

function(input, output, session) {
  output$user_email <- renderText({
    session$user
  })
}