Because a Shiny app has separate UI and server components, the interactive authentication flows require some changes. In particular, the authorization step (logging in to Azure) has to be conducted separately from the token acquisition step.
AzureAuth provides the build_authorization_uri
function
to facilitate this separation. You call this function to obtain a URI
that you browse to in order to login to Azure. Once you have logged in,
Azure will return an authorization code as part of a redirect.
Here is a skeleton Shiny app that demonstrates its use. The UI calls
build_authorization_uri
, and then redirects your browser to
that location. When you have logged in, the server captures the
authorization code and calls get_azure_token
to obtain the
token. Once the token is obtained, shinyjs
is used to
return the URL back to its original state.
library(AzureAuth)
library(shiny)
library(shinyjs)
tenant <- "your-tenant-here"
app <- "your-app-id-here"
# the Azure resource permissions needed
# if your app doesn't use any Azure resources (you only want to do authentication),
# set the resource to "openid" only
resource <- c("https://management.azure.com/.default", "openid")
# set this to the site URL of your app once it is deployed
# this must also be the redirect for your registered app in Azure Active Directory
redirect <- "http://localhost:8100"
port <- httr::parse_url(redirect)$port
options(shiny.port=if(is.null(port)) 80 else as.numeric(port))
# replace this with your app's regular UI
ui <- fluidPage(
useShinyjs(),
verbatimTextOutput("token")
)
ui_func <- function(req)
{
opts <- parseQueryString(req$QUERY_STRING)
if(is.null(opts$code))
{
auth_uri <- build_authorization_uri(resource, tenant, app, redirect_uri=redirect, version=2)
redir_js <- sprintf("location.replace(\"%s\");", auth_uri)
tags$script(HTML(redir_js))
}
else ui
}
# code for cleaning url after authentication
clean_url_js <- sprintf(
"
$(document).ready(function(event) {
const nextURL = '%s';
const nextTitle = 'My new page title';
const nextState = { additionalInformation: 'Updated the URL with JS' };
// This will create a new entry in the browser's history, without reloading
window.history.pushState(nextState, nextTitle, nextURL);
});
", redirect
)
server <- function(input, output, session)
{
shinyjs::runjs(clean_url_js)
opts <- parseQueryString(isolate(session$clientData$url_search))
if(is.null(opts$code))
return()
# this assumes your app has a 'public client/native' redirect:
# if it is a 'web' redirect, include the client secret as the password argument
token <- get_azure_token(resource, tenant, app, auth_type="authorization_code",
authorize_args=list(redirect_uri=redirect), version=2,
use_cache=FALSE, auth_code=opts$code)
output$token <- renderPrint(token)
}
shinyApp(ui_func, server)
Note that this process is only necessary within a web app, and only
when using an interactive authentication flow. In a normal R session, or
when using the client credentials or resource owner grant flows, you can
simply call get_azure_token
directly.