# This is almost a copy of auth.R file but for clients
# Only wto tweaks:
# - the default client is provided by rtweet and stored as rtweet.
# - the path to save clients is under a directory clients
#' Set default client for the current session
#'
#' `client_as()` sets up the default client used by rtweet API calls with PKCE. See [rtweet_user()] to learn more about the three
#' available authentication options.
#'
#' @param client One of the following options:
#' * `NULL`, the default, will look for rtweet's "default" authentication
#' which uses your personal default Twitter client. If it's not found, it will
#' call [client_setup_default()] to set it up.
#' * A string giving the name of a saved auth file made by [client_save()].
#' * A client object created by [rtweet_client()].
#' @return Invisibly returns the previous authentication mechanism.
#' @family client
#' @export
#' @examples
#' \dontrun{
#' # Use app auth for the remainder of this session:
#' my_app <- rtweet_app()
#' auth_as(my_app)
#'
#' # Switch back to the default user based auth
#' client_as()
#' client_list()
#' }
client_as <- function(client = NULL) {
old <- .state$client
.state$client <- find_client(client)
invisible(old)
}
#' @rdname client_setup_default
#' @export
client_has_default <- function() {
file.exists(client_path("rtweet.rds"))
}
client_path <- function(...) {
# Use private option to make testing easier
path <- getOption("rtweet:::config_dir", tools::R_user_dir("rtweet", "config"))
file.path(path, "clients", ...)
}
#' Get the current client
#'
#' If no client has been set up for this session, `client_get()` will
#' call [client_as()] to set it up.
#' @return The current client used.
#' @export
#' @family client
#' @examples
#' \dontrun{
#' client_get()
#' }
client_get <- function() {
if (is.null(.state$client)) {
client_as()
}
.state$client
}
is_client <- function(client) {
inherits(client, "httr2_oauth_client")
}
default_client <- function(client_id = NULL, client_secret = NULL) {
if (is.null(client_id) && is.null(client_secret)) {
# The sysdat file is in #./R and loaded automagically
abort(c("The default rtweet client is no longer authorized.",
i = "You'll need to register as developer in order to use the Twitter API."),
call = caller_env())
client_id <- decrypt(sysdat$e914c55d2f)
client_secret <- decrypt(sysdat$d5571d4003)
} else {
stopifnot(is_string(client_id), is_string(client_secret))
}
return(c(id = client_id, secret = client_secret))
}
default_cached_client <- function() {
if (client_has_default()) {
return(readRDS(client_path("rtweet.rds")))
}
client_str <- default_client()
rtweet_client(client_str["id"], client_str["secret"], "rtweet")
}
#' Save an authentication mechanism for use in a future session
#'
#' Use `client_save()` with [client_as()] to avoid repeatedly entering app
#' credentials, making it easier to share auth between projects.
#' Use `client_list()` to list all saved credentials.
#'
#' The tokens are saved on the clients folder in `tools::R_user_dir("rtweet", "config")`.
#'
#' @param client A client [rtweet_client()].
#' @return Invisible the path where the client is saved.
#' @family client
#' @seealso [auth_sitrep()] to help finding and managing authentications.
#' @export
#' @examples
#' \dontrun{
#' # save app client for use in other sessions
#' client <- rtweet_client()
#' client_save(client)
#'
#' # later, in a different session...
#' client_as("my-app")
#' # Show all authentications stored
#' client_list()
#' }
client_save <- function(client) {
stopifnot(is_client(client))
name <- paste0(client$name, ".rds")
path <- client_path(name)
inform(paste0("Saving client to '", path, "'"))
dir.create(client_path(), showWarnings = FALSE, recursive = TRUE)
saveRDS(client, path)
invisible(path)
}
#' @export
#' @rdname client_save
client_list <- function() {
paths <- dir(client_path(), pattern = "\\.rds$")
tools::file_path_sans_ext(paths)
}
find_client <- function(client = NULL) {
if (is.null(client)) {
no_client()
} else if (is_client(client)) {
client <- client
} else if (is_string(client)) {
client <- load_client(client)
} else {
abort("Unrecognised input to `client`", call = current_call())
}
inform(paste("Using client", client$name))
client
}
load_client <- function(client_name) {
if (file.exists(client_name) && !dir.exists(client_name)) {
path <- client_name
} else {
path <- client_path(paste0(client_name, ".rds"))
}
if (!file.exists(path) && !is_developing()) {
abort(paste0("Can't find saved client with name '", client_name, "'"),
call = current_call())
} else if (!file.exists(path)) {
return(NULL)
}
if (!is_developing()) {
inform(paste0("Reading client from '", path, "'"))
}
readRDS(path)
}
no_client <- function(call = caller_env()) {
if (is_testing()) {
testthat::skip("Client not available")
} else {
abort(c("Could not find client", i = "Find which you have with `client_list()`"), call = sys.call(1))
}
}
#' Client
#'
#' Set up your client mechanism for the Twitter API.
#' @inheritParams rtweet_user
#' @param scopes Default scopes allowed for users using this client.
#' Leave `NULL` to allow everything or choose yours with `set_scopes()`.
#' @param app Name of the client, it helps if you make it match with the name of your app.
#' On the Twitter app the Callback URI must be `http://127.0.0.1:1410/`
#' (the trailing / must be included).
#' @seealso scopes
#' @export
#' @examples
#' \donttest{
#' if (interactive()) {
#' rtweet_client()
#' }
#' }
rtweet_client <- function(client_id, client_secret,
app, scopes = NULL) {
# The default rtweet client no longer works
# if (missing(client_id) && missing(client_secret) ) {
# dc <- default_client()
# client_id <- dc[1]
# client_secret <- dc[2]
# app <- "rtweet"
# }
if (missing(client_id) && interactive()) {
client_id <- ask_pass("client ID key")
}
if (missing(client_secret) && interactive()) {
client_secret <- ask_pass("client secret")
}
stopifnot(is_string(client_id), is_string(client_secret))
if (is.null(scopes)) {
scopes <- all_scopes
} else {
scopes <- check_scopes(scopes)
}
client <- httr2::oauth_client(
id = client_id,
secret = client_secret,
token_url = "https://api.twitter.com/2/oauth2/token",
auth = "header",
name = app)
attr(client, "scopes") <- scopes
client
}
#' Set up default client
#'
#' You'll need to run this function once per computer so that rtweet can use
#' your client.
#'
#' It will use the current default account for rtweet and save them as "rtweet".
#' If a default is found it will use it instead.
#' @return
#' `client_setup_default()`: Invisibly returns the previous authentication mechanism.
#' `client_has_default()`: A logical value `TRUE` if there is a default authentication.
#' @export
#' @family client
#' @examples
#' \dontrun{
#' if (!client_has_default()) {
#' client_setup_default()
#' }
#' }
client_setup_default <- function() {
if (client_has_default()) {
inform("Using default client available.")
} else {
abort(c("The default rtweet client is no longer authorized.",
i = "You'll need to register as developer in order to use the Twitter API."),
call = current_call())
client <- rtweet_client(decrypt(sysdat$DYKcJfBkgMnGveI),
decrypt(sysdat$MRsnZtaKXqGYHju),
app = "rtweet")
client_save(client)
}
client_as("rtweet")
invisible(client_get())
}
client_scopes <- function(client) {
if (!is_client(client)) {
abort(c("Missing client.",
">" = "Check the vignette('auth', 'rtweet')",
"i" = "Get one with `rtweet_client()`"), call = call)
}
attr(client, "scopes", exact = TRUE)
}
client_app <- function(client) {
stopifnot(is_client(client))
client$name
}
#' Clean clients
#'
#' Removes the rtweet clients directory.
#' @returns Either TRUE if folder could be deleted or FALSE.
#' @export
#' @examples
#' client_clean()
client_clean <- function() {
out <- unlink(client_path(), recursive = TRUE, force = TRUE)
invisible(out == 0L)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.