22# '
33# ' This function retrieves an Azure token for a specified resource.
44# '
5- # ' If the environment variables `AZ_TENANT_ID`, `AZ_CLIENT_ID` and
6- # ' `AZ_APP_SECRET` are all set, it will try to use these to return a token .
5+ # ' It will try to get a managed token when used within a managed resource such
6+ # ' as Azure VM or Azure App Service .
77# '
8- # ' Otherwise it will try to get a managed token from a managed resource such as
9- # ' Azure VM or Azure App Service.
10- # '
11- # ' If neither of these approaches has returned a token, it will try to retrieve
12- # ' a user token using the provided parameters, requiring the user to have
13- # ' authenticated using their device. If `force_refresh` is set to `TRUE`, a
14- # ' fresh web authentication process should be launched. Otherwise it will
15- # ' attempt to use a cached token matching the given `resource`, `tenant` and
16- # ' `aad_version`.
8+ # ' If this method does not return a token, it will try to retrieve a user token
9+ # ' using the provided parameters, requiring the user to have authenticated
10+ # ' using their device. If `force_refresh` is set to `TRUE`, a fresh web
11+ # ' authentication process should be launched. Otherwise it will attempt to use
12+ # ' a cached token matching the given `resource`, `tenant` and `aad_version`.
1713# '
1814# ' @param resource For v1, a simple URL such as `"https://storage.azure.com/"`
19- # ' should be supplied.For v2, a vector specifying the URL of the Azure resource
20- # ' for which the token is requested as well as any desired scopes. See
21- # ' [AzureAuth::get_azure_token] for details. Use [generate_resource]
22- # ' to help provide an appropriate string or vector. The values default to
23- # ' `c("https://storage.azure.com/.default", "openid", "offline_access")`.
15+ # ' should be supplied. For v2, a vector specifying the URL of the Azure
16+ # ' resource for which the token is requested as well as any desired scopes.
17+ # ' See [AzureAuth::get_azure_token] for details. Use [generate_resource]
18+ # ' to help provide an appropriate string or vector.
2419# ' If setting version to 2, ensure that the `aad_version` argument is also set
2520# ' to 2. Both are set to use AAD version 1 by default.
2621# ' @param tenant A string specifying the Azure tenant. Defaults to
2722# ' `"common"`. See [AzureAuth::get_azure_token] for other values.
28- # ' @param client_id A string specifying the application ID (client ID). If
23+ # ' @param client_id A string specifying the application ID (aka client ID). If
2924# ' `NULL`, (the default) the function attempts to obtain the client ID from the
3025# ' Azure Resource Manager token, or prompts the user to log in to obtain it.
3126# ' @param auth_method A string specifying the authentication method. Defaults to
32- # ' `"authorization_code"`. See [AzureAuth::get_azure_token] for other values.
27+ # ' `"authorization_code"`. To use a secret, pass `"client_credentials"` instead
28+ # ' and provide the secret using the `password` argument in `...`. See
29+ # ' [AzureAuth::get_azure_token] for more information.
3330# ' @param aad_version Numeric. The AAD version, either 1 or 2 (1 by default)
34- # ' @param force_refresh Boolean: whether to use a stored token if available
31+ # ' @param force_refresh logical. Whether to use a stored token if available
3532# ' (`FALSE`, the default), or try to obtain a new one from Azure (`TRUE`).
3633# ' This may be useful if you wish to generate a new token with the same
3734# ' `resource` value as an existing token, but a different `tenant` or
38- # ' `auth_method`. Note that you can also try using [refresh_token] which will
35+ # ' `auth_method`. Note that you can also try [refresh_token], which should
3936# ' cause an existing token to refresh itself, without obtaining a new token
4037# ' from Azure via online reauthentication
41- # ' @param ... Optional arguments (`token_args` or `use_cache`) to be passed on
42- # ' to [AzureAuth::get_managed_token] or [AzureAuth::get_azure_token].
38+ # ' @param ... Optional arguments (eg `token_args` or `use_cache`) to be passed
39+ # ' on to [AzureAuth::get_managed_token] or [AzureAuth::get_azure_token], for
40+ # ' example to overwrite any opf their default values or to supply a `password`
4341# '
4442# ' @returns An Azure token object
4543# ' @examples
5856# '
5957# ' # Get a token using a specific app ID
6058# ' token <- get_auth_token(client_id = "my-app-id")
59+ # '
60+ # ' # Use a secret
61+ # ' token <- get_auth_token(
62+ # ' tenant = "my-tenant-id",
63+ # ' client_id = "my-app-id",
64+ # ' auth_method = "client_credentials",
65+ # ' password = "123459878&%^"
66+ # ' )
6167# ' }
6268# ' @export
6369get_auth_token <- function (
@@ -73,52 +79,49 @@ get_auth_token <- function(
7379 aad_version <- check_that(aad_version , \(x ) x %in% seq(2 ), aad_msg )
7480
7581 safely_get_token <- \(... ) purrr :: safely(AzureAuth :: get_azure_token )(... )
76- get_azure_token <- purrr :: partial(
77- safely_get_token ,
78- resource = resource ,
79- version = aad_version
80- )
81- possibly_get_mtk <- \(... ) purrr :: possibly(AzureAuth :: get_managed_token )(... )
82+ possibly_get_mgdt <- \(... ) purrr :: possibly(AzureAuth :: get_managed_token )(... )
8283
8384 dots <- rlang :: list2(... )
8485 # If the user specifies force_refresh = TRUE we turn off `use_cache`,
85- # otherwise we leave `use_cache` as it is (or as `NULL`, its default value)
86- use_cached <- ! force_refresh && (dots [[" use_cache" ]] %|| % TRUE )
87- dots <- rlang :: dots_list(!!! dots , use_cache = use_cached , .homonyms = " last" )
88-
89- # We have 4 approaches to get a token, depending on the context
90- # 1. Use environment variables if all three are set
91- token_resp <- rlang :: inject(try_token_from_vars(get_azure_token , !!! dots ))
92- token <- token_resp [[" result" ]]
93- token_error <- token_resp [[" error" ]]
86+ # otherwise we leave `use_cache` as it is
87+ if (force_refresh ) {
88+ use_cached <- FALSE
89+ } else {
90+ use_cached <- dots [[" use_cache" ]] # NULL by default if not supplied by user
91+ }
92+ dots <- rlang :: dots_list(... , use_cache = use_cached , .homonyms = " last" )
9493
95- # 2. Try to get a managed token (for example on Azure VM, App Service)
96- if (is.null(token ) && imds_available()) {
97- token <- rlang :: inject(possibly_get_mtk(resource , !!! dots ))
94+ # We have 3 approaches to get a token, depending on the context
95+ # 1. Try to get a managed token (for example on Azure VM, App Service)
96+ if (imds_available()) {
97+ token <- rlang :: inject(possibly_get_mgdt(resource , !!! dots ))
98+ } else {
99+ token <- NULL
98100 }
99101
100- # 3 . If neither of those has worked, try to get an already stored user token
101- # (unless `force_refresh` is on, in which case skip to option 4 )
102+ # 2 . If that hasn't worked, try to get an already stored user token
103+ # (unless `force_refresh` is on, in which case skip to option 3 )
102104 if (is.null(token ) && use_cached ) {
103105 token <- match_cached_token(resource , tenant , aad_version )
104106 }
105107
106- # 4 . If we still don't have a token, try to get a new one via reauthentication
108+ # 3 . If we still don't have a token, try to get a new one via reauthentication
107109 if (is.null(token )) {
108110 if (! force_refresh ) {
109111 cli :: cli_alert_info(" No matching cached token found: fetching new token" )
110112 }
111- client_id <- client_id %|| % get_client_id()
112113 token_resp <- rlang :: inject(
113- get_azure_token(
114+ safely_get_token(
115+ resource = resource ,
114116 tenant = tenant ,
115- app = client_id ,
117+ app = client_id % || % get_client_id() ,
116118 auth_type = auth_method ,
119+ version = aad_version ,
117120 !!! dots
118121 )
119122 )
120123 token <- token_resp [[" result" ]]
121- token_error <- token_error % || % token_resp [[" error" ]]
124+ token_error <- token_resp [[" error" ]]
122125 }
123126
124127 # Give some helpful feedback if the steps above have not succeeded
@@ -141,33 +144,8 @@ get_auth_token <- function(
141144}
142145
143146
144- # ' Get token via app and secret environment variables
145- # ' Sub-routine for `get_auth_token()`
146- # ' @keywords internal
147- # ' @returns A list with elements `result` and `error`. If this method is
148- # ' successful, the `result` element will contain a token.
149- try_token_from_vars <- function (get_token_fun , ... ) {
150- tenant_id_env <- Sys.getenv(" AZ_TENANT_ID" )
151- client_id_env <- Sys.getenv(" AZ_CLIENT_ID" )
152- client_secret <- Sys.getenv(" AZ_APP_SECRET" )
153-
154- if (all(nzchar(c(tenant_id_env , client_id_env , client_secret )))) {
155- rlang :: inject(
156- get_token_fun(
157- tenant = tenant_id_env ,
158- app = client_id_env ,
159- password = client_secret ,
160- ...
161- )
162- )
163- } else {
164- list (result = NULL , error = NULL )
165- }
166- }
167-
168-
169147# ' Find an already cached token that matches desired parameters
170- # ' Sub-routine for ` get_auth_token()`
148+ # ' Sub-routine for [ get_auth_token]
171149# ' @keywords internal
172150# ' @returns A token from local cache, or NULL if none matches
173151match_cached_token <- function (resource , tenant , aad_version ) {
@@ -193,7 +171,7 @@ match_cached_token <- function(resource, tenant, aad_version) {
193171}
194172
195173
196- # ' Sub-routine for ` get_auth_token()`
174+ # ' Sub-routine for [ get_auth_token]
197175# '
198176# ' Pulled out mainly to tidy up the main function code a bit
199177# ' @keywords internal
@@ -264,12 +242,12 @@ generate_resource <- function(
264242# ' Use a token's internal `refresh()` method to refresh it
265243# '
266244# ' This method avoids the need to refresh by re-authenticating online. It seems
267- # ' like this only works with v1 tokens. v2 tokens always seem to refresh by
268- # ' re-authenticating with Azure online. But v2 tokens _ought_ to refresh
269- # ' automatically and not need manual refreshing. To instead generate a
270- # ' completely fresh token, pass `use_cache = FALSE` or `force_refresh = TRUE`
271- # ' to [get_auth_token].
245+ # ' that this only works with v1 tokens. (v2 tokens always seem to refresh via
246+ # ' online re-authentication, but they _ought_ to refresh automatically.)
247+ # ' To instead generate a completely fresh token, set `force_refresh = TRUE` in
248+ # ' [get_auth_token]
272249# ' @param token An Azure authentication token
250+ # ' @rdname get_auth_token
273251# ' @returns An Azure authentication token
274252# ' @export
275253refresh_token <- \(token ) token $ refresh()
0 commit comments