rstudio/plumber

New hook after route has been found but before it's been evaluated

Open

#946 opened on Mar 7, 2024

View on GitHub
 (1 comment) (7 reactions) (0 assignees)R (1,437 stars) (257 forks)batch import
difficulty: intermediateeffort: lowhelp wantedtheme: middleware

Description

Background

My R application is a microservice that calls a larger service to authenticate requests. I need to do this for every request so that only authorized users are able to use my service. I currently have it implemented something like this:

#* @filter auth
auth <- function (req, res) {
    is_valid = expensive_token_checking(...)
    if (!is_valid) {
        res$status <- 401
        return(list(error = "Invalid token"))
    } else {
        plumber::forward()
    }
}

#* @get /foo
function (req, res) {
    ...
}

#* @get /bar
function (req, res) {
    ...
}

This works as expected, however, bots are attempting to scan my service looking for common vulnerabilities which means I have spikes of traffic looking for generic routes like /.htaccess. The issue here is that for requests which do not have a matching route, I don't want to waste my server's resources. I'd like to greedily return a 404 without needing to perform the expensive action of checking the token.

As currently implemented, these requests make it to my middleware even though the are invalid. Even if they had valid tokens, they would make it through my middleware and then receive a 404 from plumber.

Attempted solution

I tried to solve this with hooks. I tried to move my middleware into a hook that way I could leverage plumber's validation of the request while also being able to define reusable code that rejects unauthorized requests, but it appears that neither preroute or postroute hooks work as I need them to.

The preroute hook seems to evaluate before the request has found the endpoint that can handle it (which makes sense), and postroute appears to run after the code inside my route has executed. So neither really work for me. I need some way to execute code after plumber has validated that the verb + route combo is valid and before my route has actually executed.

Proposed solution

I might be misunderstanding what postroute is supposed to do. I would have expected it to intervene in the exact moment I needed it to and then I would use postserialize to execute code after my route, but ideally there would be a new kind of hook introduce that allowed me to hook into the point in the execution I need to leverage. Perhaps postvalidation or postroutefound? Those aren't great names, but just off the top of my head.

If I am misunderstanding hooks and there is a way to achieve exactly what I want to, I apologize. The conclusions I wrote above are from adding logging into each possible hook and a test route to check the order they execute.

Contributor guide