Out of the box RestRserve provides two authentication schemas: Basic
and Bearer
.
Note that Basic authentication, should only be used over HTTPS (SSL) or within secure network. In HTTP protocol Authorization
header (as well as other parts of the HTTP request) are plain text and are not encrypted!
According to AuthBackendBasic
documentation first of all we need to provide an authentication function. It should take 2 arguments - user
and password
and return logical
value - whether access is allowed for a given user or not.
library(RestRserve)
= list(
allowed_access "user-1" = "password-1",
"user-2" = "password-2"
)
= function(user, password) {
auth_fun = FALSE
res try({
= identical(allowed_access[[user]], password)
res silent = TRUE)
}, return(res)
}
Now we can create authentication backend.
= AuthBackendBasic$new(FUN = auth_fun) basic_auth_backend
Now let’s create application which requires authorization in order to use /secure/factorial
endpoint:
= AuthMiddleware$new(
auth_mw auth_backend = basic_auth_backend,
routes = "/secure/factorial",
id = "auth_middleware"
)
= Application$new(middleware = list(auth_mw)) app
Let’s add two endpoints - first public (/factorial
) and second with restricted access (/secure/factorial
):
= function(.req, .res) {
factorial_handler = .req$get_param_query("x")
x = as.integer(x)
x $set_body(factorial(x))
.res
}$add_get("/factorial", factorial_handler)
app$add_get("/secure/factorial", factorial_handler) app
As we can see first endpoint doesn’t require any authentication:
= Request$new(path = "/factorial", parameters_query = list(x = "5"))
req = app$process_request(req)
res $body
res#> [1] 120
Let’s try to send a request without credentials to the second endpoint:
= Request$new(path = "/secure/factorial", parameters_query = list(x = "5"))
req = app$process_request(req)
res $body
res#> [1] "401 Missing Authorization Header"
As expected this gives 405
error.
Now let’s add correct credentials:
= jsonlite::base64_enc("user-1:password-1")
credentials = list("Authorization" = sprintf("Basic %s", credentials))
headers
= Request$new(
req path = "/secure/factorial",
parameters_query = list(x = "5"),
headers = headers
)
= app$process_request(req)
res $body
res#> [1] 120
Success!
Let’s see what happens if password is wrong:
= jsonlite::base64_enc("user-1:password-2")
credentials = list("Authorization" = sprintf("Basic %s", credentials))
headers
= Request$new(
req path = "/secure/factorial",
parameters_query = list(x = "5"),
headers = headers
)
= app$process_request(req)
res $body
res#> [1] "401 Invalid Username/Password"
Bearer
authentication (also called “token” authentication) is an HTTP authentication scheme that involves security tokens called bearer tokens. The name “Bearer authentication” can be understood as “give access to the bearer of this token.” The bearer token is a cryptic string, usually generated by the server in response to a login request. The client must send this token in the Authorization header when making requests to protected resources.
The Bearer
authentication scheme was originally created as part of OAuth 2.0
in RFC 6750, but is sometimes also used on its own. Similarly to Basic authentication, Bearer authentication should only be used over HTTPS (SSL).
= c(
allowed_tokens "super_secure_token_1",
"super_secure_token_2"
)
= function(token) {
auth_fun = FALSE
res try({
= token %in% allowed_tokens
res silent = TRUE)
}, return(res)
}= AuthBackendBearer$new(FUN = auth_fun) basic_auth_backend
As an alternative to requiring authentication for a single endpoint we can make it mandatory for all endpoints which start with certain pattern:
= AuthMiddleware$new(
auth_mw auth_backend = basic_auth_backend,
routes = "/secure/",
match = "partial",
id = "auth_middleware"
)= Application$new(middleware = list(auth_mw)) app
For example:
$add_get("/hello0", function(req, res) {res$body = "OK"})
app$add_get("/secure/hello1", function(req, res) {res$body = "OK"})
app$add_get("/secure/hello2", function(req, res) {res$body = "OK"}) app
Request with valid token to /secure/hello1
:
= list("Authorization" = "Bearer super_secure_token_1")
headers = Request$new(
req path = "/secure/hello1",
headers = headers
)
= app$process_request(req)
res $body
res#> [1] "OK"
Request with invalid token to /secure/hello2
:
= list("Authorization" = "Bearer abcd")
headers = Request$new(
req path = "/secure/hello2",
headers = headers
)
= app$process_request(req)
res $body
res#> [1] "401 Invalid Token"
Request to endpoint which doesn’t require authorization: /hello0
:
= Request$new(path = "/hello0")
req = app$process_request(req)
res $body
res#> [1] "OK"