Securely Incorporate Login Credentials Into R Scripts
There are two main functions in rcreds
WRITE functions: write_credentials_to_file()
and the database version write_db_credentials_to_file()
READ functions: read_credentials_from_file()
and the database version read_db_credentials_from_file()
rcreds
allows for a secure way to code scripts that require sensitive inputs such as login credentials to databases, APIs, or other systems. Users can securely write their credentials and other sensitive information to an encrypted file on disk, and then later read those credentials back into R.
The main concept has been adopted from https://github.com/sdoyen/r_password_crypt/blob/master/crypt.R
Many scripts require login to other systems. The most common example is accessing data from a database.
Most comonly, a user will simply hardcode their credentials right into their code. Avoiding this practice generally involves re-inputting passwords over and over again or nesting scripts within other scripts when scheduling tasks.
We will assume that, by nature of searching out such a package we can avoid here the discussion of the why to implement a different approach (even when "I am the only one who will be using or accessing this") and simply move on to the how to use.
Generally, a user will save their credentials to a folder in ~/.rcreds
We do not want to include that as the default folder in this vignette, as the vignette examples will write meaningless examples to the users home directory.
We will use CREDS_PARENT_FOLDER
in place of ~/.rcreds
.
Let's assume you have some function which requires the use of sensitive inputs.
some_login_function <- function(username, password, separate_param) { ## does something with username/password ## ... message(sprintf("some_login_function() received username = '%s' and password = '%s' and separate_param = '%s'\n (obviously wouldn't normally output like this)", username, password, separate_param)) return(TRUE) }
The rcreds
approach would be to write the credentials to an encrypted file on disk and then read and decrypt them when needed.
The user needs to tell rcreds
where files should be written to and read from.
This can go in your ~/.Rprofile
file.
## reminder, tempdir() is only for vignette. Normally use: # CREDS_PARENT_FOLDER <- "~/.rcreds" CREDS_PARENT_FOLDER <- tempdir() library(rcreds) set_default_rcreds_folder(file.path(CREDS_PARENT_FOLDER, "credential_files")) set_default_rcreds_folder(file.path(CREDS_PARENT_FOLDER, "db_credential_files"), DB=TRUE) set_default_rcreds_key_folder(folder = file.path(CREDS_PARENT_FOLDER, "key_files"))
One time, write to disk
## reminder, tempdir() is only for vignette. Normally use: # CREDS_PARENT_FOLDER <- "~/.rcreds" CREDS_PARENT_FOLDER <- tempdir() ## in your .Rprofile, you should set the default folders. ## Replace CREDS_PARENT_FOLDER with correct folder, such as "~/.rcreds" rcreds::set_default_rcreds_folder(file.path(CREDS_PARENT_FOLDER, "credential_files")) rcreds::set_default_rcreds_folder(file.path(CREDS_PARENT_FOLDER, "db_credential_files"), DB=TRUE) rcreds::set_default_rcreds_key_folder(folder=file.path(CREDS_PARENT_FOLDER, "key_files")) library(rcreds) creds_info <- "for_app123_login" ## some description that will be part of the filename key_object <- create_key(bytes=32, depth=8, verbose=TRUE) ## Save Credentials write_credentials_to_file(username="cosmo", password="too many secrets", key=key_object, info.file_name = creds_info, verbose=TRUE) ## Save key file to a different location. save_key(key=key_object, zArchive_existing=FALSE, overwrite_existing=TRUE, verbose=TRUE)
Then in a script that needs to use the credentials, read from disk and use the list elements.
## reminder, tempdir() is only for vignette. Normally use: # CREDS_PARENT_FOLDER <- "~/.rcreds" CREDS_PARENT_FOLDER <- tempdir() key_file <- file.path(CREDS_PARENT_FOLDER, "key_files", ".crypt_key.rds") creds_file <- file.path(CREDS_PARENT_FOLDER, "credential_files", "for_app123_login.credentials.creds") creds <- read_credentials_from_file(file_full_path=creds_file, key=key_file) ## SHOWING CONTENTS FOR DEMO PURPOSES. NORMALLY DON'T DO THIS print(creds) ## Use the credentials by refering to the elements by name some_login_function(username = creds$username, password=creds$password, separate_param="plain example") ## altenatively can use do.call do.call(some_login_function, c(creds, list(separate_param="do.call example")))
Since we are writing to and reading from files, the user under which R
is running must have appropriate permissions to both: the file, and the folder in which the file is located.
When this is not the case you will receive an error that will (usually) end with probable reason 'Permission denied'
For example:
Error in gzfile(file, mode) : cannot open the connection In addition: Warning message: In gzfile(file, mode) : cannot open compressed file '/PATH/TO/FILE/file_name.crypt_key.rds', probable reason 'Permission denied'
NOTE: You will often see this when you create the key or creds file with one user and then try to use the file with a different user. eg, did you use sudo R
to create the files?
RESOLUTION: Please ensure that your user has permissions on the folder and file. (On Mac OSX and Linux systems, use chown
and/or chmod
). Stackoverflow has several questions and answers on this topic.
Please report any issues or bugs at the package's github page
All pull requests will be gladly considered.
For tips on pull requests, checkout this helpful blog post by codeinthehole
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.