From 399b51b7698abf3defb3663dedc57c483b703973 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Tue, 13 Jan 2026 14:31:52 -0500 Subject: [PATCH] Add getIdentityToken() for retrieving Workbench identity tokens. This commit introduces `getIdentityToken()`, which fetches the OpenID Connect identity token for the current user from Posit Workbench via RPC, if possible. It also updates `assertWorkbenchSession()` to issue more generic error messages since it now covers both broader functionality. Unit tests are included. Signed-off-by: Aaron Jacobs --- NAMESPACE | 1 + NEWS.md | 2 ++ R/auth.R | 34 +++++++++++++++++++++++++++++++++- _pkgdown.yml | 1 + man/getIdentityToken.Rd | 25 +++++++++++++++++++++++++ tests/testthat/test-oauth.R | 31 ++++++++++++++++++++++++++++--- 6 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 man/getIdentityToken.Rd diff --git a/NAMESPACE b/NAMESPACE index 0da8137..e53a4df 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -43,6 +43,7 @@ export(getActiveDocumentContext) export(getActiveProject) export(getConsoleEditorContext) export(getDelegatedAzureToken) +export(getIdentityToken) export(getMode) export(getOAuthCredentials) export(getOAuthIntegration) diff --git a/NEWS.md b/NEWS.md index 5754346..00fce4e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,8 @@ * `rstudioapi::documentNew()` now accepts arbitrary document types. (#316) +* Added `getIdentityToken()` for retrieving the current user's identity token + on Posit Workbench, if possible. # rstudioapi 0.17.1 diff --git a/R/auth.R b/R/auth.R index 0dc245f..e09a28e 100644 --- a/R/auth.R +++ b/R/auth.R @@ -51,6 +51,38 @@ getDelegatedAzureToken <- function(resource) { response$token } +#' Get the User's Identity Token +#' +#' Retrieve the user's OpenID Connect identity token for the current Posit +#' Workbench session, if any. This token can be used to authenticate with +#' services that trust Workbench's identity provider. +#' +#' @return A list containing: +#' \describe{ +#' \item{token}{The identity token string.} +#' \item{expiry}{The token expiry time as a POSIXct datetime object.} +#' } +#' Throws an error if the token cannot be retrieved. +#' +#' @note This function works for any IDE running within a Posit Workbench +#' session, not just RStudio. +#' +#' @export +getIdentityToken <- function() { + assertWorkbenchSession() + + response <- callWorkbenchRPC( + method = "id_token", + body = list(), + error_context = "retrieving identity token" + ) + + list( + token = response$token, + expiry = as.POSIXct(response$expiry, format = "%Y-%m-%dT%H:%M:%OS", tz = "UTC") + ) +} + #' Retrieve OAuth Credentials for Integrations #' #' Retrieve OAuth credentials for a configured OAuth integration in Posit Workbench. @@ -335,7 +367,7 @@ assertWorkbenchSession <- function() { return(invisible(NULL)) } - stop("OAuth functionality is only available within Posit Workbench sessions.") + stop("This functionality is only available within Posit Workbench sessions.") } # Internal helper to assert version requirement diff --git a/_pkgdown.yml b/_pkgdown.yml index 195d2fb..ebb7c46 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -90,6 +90,7 @@ reference: - findOAuthIntegration - getOAuthCredentials - getDelegatedAzureToken + - getIdentityToken - title : Themes desc : Work with RStudio editor themes. diff --git a/man/getIdentityToken.Rd b/man/getIdentityToken.Rd new file mode 100644 index 0000000..e180ab1 --- /dev/null +++ b/man/getIdentityToken.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/auth.R +\name{getIdentityToken} +\alias{getIdentityToken} +\title{Get the User's Identity Token} +\usage{ +getIdentityToken() +} +\value{ +A list containing: +\describe{ +\item{token}{The identity token string.} +\item{expiry}{The token expiry time as a POSIXct datetime object.} +} +Throws an error if the token cannot be retrieved. +} +\description{ +Retrieve the user's OpenID Connect identity token for the current Posit +Workbench session, if any. This token can be used to authenticate with +services that trust Workbench's identity provider. +} +\note{ +This function works for any IDE running within a Posit Workbench +session, not just RStudio. +} diff --git a/tests/testthat/test-oauth.R b/tests/testthat/test-oauth.R index 730b217..ea428be 100644 --- a/tests/testthat/test-oauth.R +++ b/tests/testthat/test-oauth.R @@ -6,17 +6,17 @@ test_that("OAuth functions fail gracefully outside Workbench", { expect_error( getOAuthCredentials("4c1cfecb-1927-4f19-bc2f-d8ac261364e0"), - "OAuth functionality is only available within Posit Workbench sessions" + "This functionality is only available within Posit Workbench sessions" ) expect_error( getOAuthIntegrations(), - "OAuth functionality is only available within Posit Workbench sessions" + "This functionality is only available within Posit Workbench sessions" ) expect_error( getOAuthIntegration("test-guid"), - "OAuth functionality is only available within Posit Workbench sessions" + "This functionality is only available within Posit Workbench sessions" ) }) @@ -109,3 +109,28 @@ test_that("getOAuthCredentials validates GUID format", { "audience must be a valid GUID" ) }) + +test_that("getIdentityToken fails gracefully outside Workbench", { + withr::local_envvar( + POSIT_PRODUCT = NA, + RS_SERVER_ADDRESS = NA + ) + + expect_error( + getIdentityToken(), + "This functionality is only available within Posit Workbench sessions" + ) +}) + +test_that("getIdentityToken handles missing RPC cookie", { + withr::local_envvar( + RS_SERVER_ADDRESS = "http://localhost:8787", + RS_SESSION_RPC_COOKIE = NA, + PWB_SESSION_RUNTIME_DIR = NA + ) + + expect_error( + getIdentityToken(), + "RPC cookie not found" + ) +})