Azure OAuth2 in Plumber

Hi all, I've done some experimentation in plumber and trying to integrate Azure OAuth2 using an authorization code, with the eventual goal of releasing this to RStudio Connect. I am having problems having the redirect in plumber go to the correct place on my local machine, which is also the same issue in RStudio Connect.

Presently, I have basic entrypoint.R file, where the <TENANT_ID> is the my Azure tenant guid:

# entrypoint.R

library(plumber)

pr$setApiSpec(function(spec) {
  spec$info$title <- "Test"
  spec$openid <- "3.0.3"
  spec$components$securitySchemes$azureoauth$type <- 'oauth2'
  spec$components$securitySchemes$azureoauth$description <- 'API key to authorize requests.'
  spec$components$securitySchemes$azureoauth$flows$authorizationCode$authorizationUrl <- 'https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/authorize'
  spec$components$securitySchemes$azureoauth$flows$authorizationCode$tokenUrl <- 'https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token'
  spec$components$securitySchemes$azureoauth$flows$authorizationCode$scopes$`https://graph.microsoft.com/User.Read` <- 'Sign in and read user profile'

  spec
})

And a vanilla plumber.R file that does nothing with it (just a literal)

# plumber.R

#* @get /hello
function(req) {
  print('hello')
}

I am able to get the authorization button and the authorizations modal to open up:

And I can click on the Authorization button and go to Azure and authorize the user. Where I run into trouble is the redirect/reply url. After it gets a code, its coming back to a 404 page that doesn't seem to exist in the root at http://localhost:8100/oauth2-redirect.html

Secondary issues:

  • I'd like to specify the client_id and client_secret by default somewhere, but I'm not sure where to put it.
  • When I deploy to RStudio Connect, the redirect goes to http://rstudioconnect.company.com/oauth2-redirect.html, versus the app itself http://rstudioconnect.company.com/appname/oauth2-redirect.html. I suspect this challenge is related to the above.

Some preliminary research indicates a callback/redirect, but not entirely sure how to pass that off (as referenced here). Does anyone have any pointers or guidance?

Thanks,

Jon

bumping to @meztez, and want to know if this is worth making an issue for if the capability alter the redirect doesn't exist at the Swagger level.

I believe this is outside of the plumber package scope. RStudio Connect already has a user access management built-in. Access can be managed per API.

https://docs.rstudio.com/connect/admin/authentication/

If you're interfacing with Azure, consider using AzureAuth. This is part of the AzureR family of packages that share a common framework for authentication.

Disclaimer: I'm the AzureR/AzureAuth dev.

Thanks @meztez for the response.

I think I'm pretty close already - I just can't seem to specify where the plumber package (whether local or docker or RStudio Connect) constructs a redirect URI back to https://<host>/__docs__/oauth2-redirect.html.

When I set the API spec to:

pr$setApiSpec(function(spec) {
  spec$components$securitySchemes$azureoauth$flows$authorizationCode$authorizationUrl <- 'https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/authorize?redirect_uri=https://<HOST>/__docs__/oauth2-redirect.html'

And click authorize, I can see there are two distinct redirect_uri specified in the query:
https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/authorize?redirect_uri=http://localhost:8100/__docs__/oauth2-redirect.html&response_type=code&client_id=<CLIENT_ID>&redirect_uri=http%3A%2F%2Flocalhost%3A8100%2Foauth2-redirect.html&scope=https%3A%2F%2Fgraph.microsoft.com%2FUser.Read&state=<SNIP>

My gut is that if I'm able to set the original redirect URI, then I'm golden.

Perhaps more reasonably, since plumber creates the /__docs__/ path, I think it would make sense to try to get that passed to the modal at that stage. Would this potentially fall into something that is a client-specific parameter? As the RStudio swagger package does provide the oauth2-redirect.html file, I'm trying to figure out where in either the RStudio/Swagger or RStudio/plumber package of the setting of the redirect is specified (and how its passed eventually to that specific Authorization modal).

Having something like this would be very useful, as we could authorize groups to access specific Azure resources, without the need to also need to pass that group via App Registration then Enterprise Application then RStudio Connect. If I'm not mistaken, I would think other plumber users would benefit as well with the OAuth2 as an authentication mechanism.

Aside, @Hong I'm trying to figure out how to build AzureAuth into this as a filter to check the token's validity/refresh before passing it along to the endpoint as well. I'm trying to figure out how to get the redirect back to plumber - I think its a bit of httpuv I'm trying to understand.

Hi @jonlin , had you managed to sort this one out please? I have exactly the same challenge.

Apologies for late reply. Unfortunately no; I've switched over to FastAPI for use cases where I need to pass a particular user's OAuth token through.

If I can use a service account's oauth2 token after the API is called, and use Posit Connect's groups gathering as a pre-filter (and gathered via the X-RSC-Authorization), then plumber is a viable option.

Thanks for getting back. I have given up on automating Swagger and passed the Bearer token directly. I hit another snag with Posit Connect then as it was intercepting the Authorisation header and failing (as it expects a Key not Bearer). I ended up using Key only as this is an internal use case.