Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for visitor api key #363

Merged
merged 12 commits into from
Jan 23, 2025
Merged

feat: add support for visitor api key #363

merged 12 commits into from
Jan 23, 2025

Conversation

toph-allen
Copy link
Collaborator

@toph-allen toph-allen commented Jan 17, 2025

Intent

Add the ability to create a Connect client using content visitor-scoped authentication.

Fixes #362

Approach

Added a token argument to the connect() function. When passed a token and running on Connect, performs an OAuth credential exchange request to get a visitor API key and returns a client using that API key instead. When an argument is provided to token but code is not running on Connect, prints a message and returns a client using the provided API key.

I considered a few tradeoffs:

  • The general convention in R is to indicate optional arguments by giving them a default NULL value. This implementation breaks with the convention — token argument has no default value, and I use missing() to tell if it has been provided.
    • The default value for missing HTTP headers in R is NULL, so sticking to convention means that we can't tell the difference between the cases where a user just wants to use the API key, or is using the token arg but running the content locally.
    • This is actually fine wrt functionality, because doing this leads to the correct behavior of, when token is provided correctly, using the API key locally but using the token on Connect.
    • However, I decided to break with the default NULL arg convention because this allows us to log a console message when the content is running locally and we see that they provided a NULL arg to token and are using the API key.
  • The token argument actually comes before the pre-existing prefix argument. This is fine, I think: the prefix argument would be used when users want to set the env var value of both server and api_key, the first two arguments, so it should basically never be called with them — which means it would always be called by name and not positionally, and is fine to move. The token argument makes more sense to be up front with those two, although it's unlikely to ever be called positionally, because I doubt you'd ever call it and also pass in a server URL.
  • The new logic was added in the connect() function, rather than the Connect object's Connect$new() initialization function. This… just made more sense to me. This is logic that wraps the direct initialization of the object.
    • Currently, the way that messaging happens inside connect(), when you use a token on Connect, the app logs will contain the line Defining Connect with the server: {server} twice. This is because that line is logged from Connect$new(). I guess we could move that log line out of that function, but that didn't seem like a huge priority. And technically, both clients are defined, because the first one is used to make the OAuth request.
  • I named the arg for the fallback API key token_fallback_api_key which is kinda verbose — I wanted to clarify that it wasn't, like, just a fallback API key that's used if the regular api_key is not present.

Manual Verification

You can test this with the following Shiny app:

library(shiny)
library(connectapi)

ui <- fluidPage(
  "Publisher",
  verbatimTextOutput("publisher_username"),
  verbatimTextOutput("publisher_api_key"),
  "Viewer",
  verbatimTextOutput("viewer_username"),
  verbatimTextOutput("viewer_api_key")
)

server <- function(input, output, session) {
  # Create a publisher client for comparison. This is not needed to create a viewer client.
  publisher_client <- connect()

  # Read the user-session-token header and create a viewer client
  user_session_token <- session$request$HTTP_POSIT_CONNECT_USER_SESSION_TOKEN
  viewer_client <- connect(token = user_session_token)

  output$publisher_username <- renderText(paste("username:", publisher_client$GET("v1/user")$username))
  output$publisher_api_key <- renderText(paste("api key:", publisher_client$api_key))
  output$viewer_username <- renderText(paste("username:", viewer_client$GET("v1/user")$username))
  output$viewer_api_key <- renderText(paste("api key:", viewer_client$api_key))
}

shinyApp(ui, server)

To publish this to Connect with the dev version of connectapi:

  1. Place this app in a directory in a file named app.R.
  2. In an R console, run renv::init(), renv::install("posit-dev/connectapi@toph/viewer-api-key"), and renv::snapshot().
  3. Publish to Connect.

Checklist

  • Does this change update NEWS.md (referencing the connected issue if necessary)?
  • Does this change need documentation? Have you run devtools::document()?

@toph-allen toph-allen changed the title feat: add support for viewer api key [draft] feat: add support for viewer api key Jan 17, 2025
@toph-allen toph-allen marked this pull request as ready for review January 17, 2025 23:06
R/connect.R Outdated Show resolved Hide resolved
R/connect.R Outdated Show resolved Hide resolved
Copy link

@mconflitti-pbc mconflitti-pbc left a comment

Choose a reason for hiding this comment

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

Couple suggestions but overall looks good

@mconflitti-pbc
Copy link

Only other comment is that the posit-sdk-py side of this is on hold until I can chat with Kelly about the naming convention she prefers us to use: Visitor vs Viewer across the sdks, docs, and connect server. So maybe this PR needs to be held up until then as well?

@toph-allen
Copy link
Collaborator Author

toph-allen commented Jan 21, 2025

Only other comment is that the posit-sdk-py side of this is on hold until I can chat with Kelly about the naming convention she prefers us to use: Visitor vs Viewer across the sdks, docs, and connect server. So maybe this PR needs to be held up until then as well?

@mconflitti-pbc Sounds good, I'll hold off on merging till I hear from you about that. Thanks for moving that convo forward while I'm on jury duty!

@toph-allen toph-allen changed the title feat: add support for viewer api key feat: add support for visitor api key Jan 23, 2025
R/connect.R Outdated Show resolved Hide resolved
@toph-allen toph-allen merged commit 05fd8d5 into main Jan 23, 2025
19 checks passed
@toph-allen toph-allen deleted the toph/viewer-api-key branch January 23, 2025 22:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for viewer API key
2 participants