Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
# connectapi (development version)

- When using integrations, prefer to read from `CONNECT_CONTENT_SESSION_TOKEN_FILE` to find the session token. This helps long-running processes ensure that they can maintain fresh credentials.

# connectapi 0.11.1

- `get_usage()` now returns the id column as a character to match other parts of the API (#512).

# connectapi 0.11.0

- `get_usage()` now allows for filtering by content GUID with the `content_guid`
argument. This is only available on Connect server versions 2026.01 and later.
- `get_usage()` now allows for filtering by content GUID with the `content_guid`
argument. This is only available on Connect server versions 2026.01 and later.
- The `activate` argument to `set_schedule_*()` functions is deprecated and
no longer has any effect, due to changes in the Connect API. It will be
removed in a future release. (#500)
- Added a single retry to `content_restart()` to more robustly clean up
temporary environment variables. (#498)
- Improved performance of `page_cursor()`. (#501)

## Breaking changes

- Removed `get_image`, `delete_image`, `has_image`, `set_image_path`,
Expand Down
20 changes: 17 additions & 3 deletions R/get.R
Original file line number Diff line number Diff line change
Expand Up @@ -871,8 +871,10 @@ get_oauth_credentials <- function(
#' @param content_session_token Optional. The content session token. This token
#' can only be obtained when the content is running on a Connect server. The
#' token identifies the service account integration previously configured by
#' the publisher on the Connect server. Defaults to the value from the
#' environment variable: `CONNECT_CONTENT_SESSION_TOKEN`
#' the publisher on the Connect server. Defaults to the value found in the file
#' indicated by the `CONNECT_CONTENT_SESSION_TOKEN_FILE` environment variable
#' on Connect >= 2026.02.0, or from the value of the environment variable
#' `CONNECT_CONTENT_SESSION_TOKEN` on earlier versions.
#' @param requested_token_type Optional. The requested token type. If unset,
#' will default to `urn:ietf:params:oauth:token-type:access_token`. Otherwise,
#' this can be set to `urn:ietf:params:aws:token-type:credentials` for AWS
Expand Down Expand Up @@ -918,6 +920,14 @@ get_oauth_content_credentials <- function(
error_if_less_than(connect$version, "2025.07.0")
}

# First, try CONNECT_CONTENT_SESSION_TOKEN_FILE
if (is.null(content_session_token)) {
token_file <- Sys.getenv("CONNECT_CONTENT_SESSION_TOKEN_FILE")
if (nzchar(token_file)) {
content_session_token <- readLines(token_file, n = 1, warn = FALSE)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know R primitives very well. Does the nzchar equality check handle conditions where the file specified at CONNECT_CONTENT_SESSION_TOKEN_FILE is missing? Also, will if (is.null(content_session_token)) evaluate to false if the file is empty?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nzchar is handling "is the env var set and not empty". If the file it points to does not exist, readLines() will throw an error. If the file exists but is empty, that would return a 0-length string, which would be an invalid token but not NULL so it wouldn't fall back to checking the CONNECT_CONTENT_SESSION_TOKEN env var.

We could be more defensive around those, I suppose, but what other than raising a different error message would we do? If the session token file is invalid, why should we expect anything else to work?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah yeah, I just wanted to make sure that it handled empty files in the same way as the Python implementation for consistency.

}
}
# If that doesn't exist (it was added in 2026.02.0), look for the token itself
if (is.null(content_session_token)) {
content_session_token <- Sys.getenv("CONNECT_CONTENT_SESSION_TOKEN")
if (nchar(content_session_token) == 0) {
Expand Down Expand Up @@ -1070,7 +1080,11 @@ get_aws_credentials <- function(connect, user_session_token, audience = NULL) {
#' }
#'
#' @export
get_aws_content_credentials <- function(connect, content_session_token = NULL, audience = NULL) {
get_aws_content_credentials <- function(
connect,
content_session_token = NULL,
audience = NULL
) {
error_if_less_than(connect$version, "2025.03.0")

if (!is.null(audience)) {
Expand Down
6 changes: 4 additions & 2 deletions man/get_oauth_content_credentials.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 23 additions & 1 deletion tests/testthat/test-oauth.R
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,29 @@ with_mock_api({
)
})

test_that("if there is a session token file, we prefer that", {
token_file <- tempfile()
cat("content-session-token", file = token_file)
withr::local_options(list(rlib_warning_verbosity = "verbose"))
withr::local_envvar(
list(CONNECT_CONTENT_SESSION_TOKEN_FILE = token_file)
)

client <- Connect$new(server = "https://connect.example", api_key = "fake")
expect_true(validate_R6_class(client, "Connect"))
expect_warning(
credentials <- get_oauth_content_credentials(client)
)
expect_equal(
credentials,
list(
access_token = "content-access-token",
issued_token_type = "urn:ietf:params:oauth:token-type:access_token",
token_type = "Bearer"
)
)
})

test_that("we cannot retrieve the oauth content credentials without a token or env var", {
withr::local_options(list(rlib_warning_verbosity = "verbose"))

Expand Down Expand Up @@ -124,7 +147,6 @@ with_mock_api({
client <- Connect$new(server = "https://connect.example", api_key = "fake")
expect_true(validate_R6_class(client, "Connect"))


credentials <- get_aws_content_credentials(client)

expect_equal(
Expand Down
Loading