Skip to content

Commit e8ef424

Browse files
authored
Merge pull request #101710 from v-albemi/microsoft-identity-platform-app-scenarios-daemon
edit pass: Microsoft identity platform app scenarios daemon
2 parents 8b9615f + 1dd2bfb commit e8ef424

7 files changed

+141
-130
lines changed

articles/active-directory/develop/scenario-daemon-acquire-token.md

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,18 @@ ms.workload: identity
1616
ms.date: 10/30/2019
1717
ms.author: jmprieur
1818
ms.custom: aaddev
19-
#Customer intent: As an application developer, I want to know how to write a daemon app that can call web APIs using the Microsoft identity platform for developers.
19+
20+
#Customer intent: As an application developer, I want to know how to write a daemon app that can call web APIs by using the Microsoft identity platform for developers.
21+
2022
---
2123

2224
# Daemon app that calls web APIs - acquire a token
2325

24-
Once the confidential client application is constructed, you can acquire a token for the app by calling ``AcquireTokenForClient``, passing the scope, and forcing or not a refresh of the token.
26+
After you've constructed a confidential client application, you can acquire a token for the app by calling `AcquireTokenForClient`, passing the scope, and optionally forcing a refresh of the token.
2527

2628
## Scopes to request
2729

28-
The scope to request for a client credential flow is the name of the resource followed by `/.default`. This notation tells Azure AD to use the **application level permissions** declared statically during the application registration. Also, as seen previously, these API permissions must be granted by a tenant administrator
30+
The scope to request for a client credential flow is the name of the resource followed by `/.default`. This notation tells Azure Active Directory (Azure AD) to use the *application-level permissions* declared statically during application registration. Also, these API permissions must be granted by a tenant administrator.
2931

3032
# [.NET](#tab/dotnet)
3133

@@ -36,7 +38,7 @@ var scopes = new [] { ResourceId+"/.default"};
3638

3739
# [Python](#tab/python)
3840

39-
In MSAL Python, the configuration file would look like the following code snippet:
41+
In MSAL Python, the configuration file looks like this code snippet:
4042

4143
```Json
4244
{
@@ -52,26 +54,26 @@ final static String GRAPH_DEFAULT_SCOPE = "https://graph.microsoft.com/.default"
5254

5355
---
5456

55-
### Case of Azure AD (v1.0) resources
57+
### Azure AD (v1.0) resources
5658

57-
The scope used for client credentials should always be resourceId+"/.default"
59+
The scope used for client credentials should always be the resource ID followed by `/.default`.
5860

5961
> [!IMPORTANT]
60-
> For MSAL asking an access token for a resource accepting a v1.0 access token, Azure AD parses the desired audience from the requested scope by taking everything before the last slash and using it as the resource identifier.
61-
> Therefore if, like Azure SQL (**https://database.windows.net**) the resource expects an audience ending with a slash (for Azure SQL: `https://database.windows.net/`), you'll need to request a scope of `https://database.windows.net//.default` (note the double slash). See also MSAL.NET issue [#747](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/747): Resource url's trailing slash is omitted, which caused sql auth failure.
62+
> When MSAL requests an access token for a resource that accepts a version 1.0 access token, Azure AD parses the desired audience from the requested scope by taking everything before the last slash and using it as the resource identifier.
63+
> So if, like Azure SQL Database (**https:\//database.windows.net**), the resource expects an audience that ends with a slash (for Azure SQL Database, `https://database.windows.net/`), you'll need to request a scope of `https://database.windows.net//.default`. (Note the double slash.) See also MSAL.NET issue [#747: Resource url's trailing slash is omitted, which caused sql auth failure](https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/747).
6264
6365
## AcquireTokenForClient API
6466

65-
To acquire a token for the app, you'll use `AcquireTokenForClient` or the equivalent depending on the platforms.
67+
To acquire a token for the app, you'll use `AcquireTokenForClient` or its equivalent, depending on the platform.
6668

6769
# [.NET](#tab/dotnet)
6870

6971
```csharp
7072
using Microsoft.Identity.Client;
7173

72-
// With client credentials flows the scopes is ALWAYS of the shape "resource/.default", as the
74+
// With client credentials flows, the scope is always of the shape "resource/.default" because the
7375
// application permissions need to be set statically (in the portal or by PowerShell), and then granted by
74-
// a tenant administrator
76+
// a tenant administrator.
7577
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
7678

7779
AuthenticationResult result = null;
@@ -82,14 +84,14 @@ try
8284
}
8385
catch (MsalUiRequiredException ex)
8486
{
85-
// The application does not have sufficient permissions
86-
// - did you declare enough app permissions in during the app creation?
87-
// - did the tenant admin needs to grant permissions to the application.
87+
// The application doesn't have sufficient permissions.
88+
// - Did you declare enough app permissions during app creation?
89+
// - Did the tenant admin grant permissions to the application?
8890
}
8991
catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
9092
{
91-
// Invalid scope. The scope has to be of the form "https://resourceurl/.default"
92-
// Mitigation: change the scope to be as expected !
93+
// Invalid scope. The scope has to be in the form "https://resourceurl/.default"
94+
// Mitigation: Change the scope to be as expected.
9395
}
9496
```
9597

@@ -99,27 +101,27 @@ catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
99101
# The pattern to acquire a token looks like this.
100102
result = None
101103

102-
# Firstly, looks up a token from cache
103-
# Since we are looking for token for the current app, NOT for an end user,
104-
# notice we give account parameter as None.
104+
# First, the code looks up a token from the cache.
105+
# Because we're looking for a token for the current app, not for a user,
106+
# use None for the account parameter.
105107
result = app.acquire_token_silent(config["scope"], account=None)
106108

107109
if not result:
108110
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
109111
result = app.acquire_token_for_client(scopes=config["scope"])
110112

111113
if "access_token" in result:
112-
# Call a protected API with the access token
114+
# Call a protected API with the access token.
113115
print(result["token_type"])
114116
else:
115117
print(result.get("error"))
116118
print(result.get("error_description"))
117-
print(result.get("correlation_id")) # You may need this when reporting a bug
119+
print(result.get("correlation_id")) # You might need this when reporting a bug.
118120
```
119121

120122
# [Java](#tab/java)
121123

122-
This is an extract from the [MSAL Java dev samples](https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/dev/src/samples/confidential-client/).
124+
This code is extracted from the [MSAL Java dev samples](https://github.com/AzureAD/microsoft-authentication-library-for-java/blob/dev/src/samples/confidential-client/).
123125

124126
```Java
125127
ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder(
@@ -135,7 +137,7 @@ BiConsumer<IAuthenticationResult, Throwable> processAuthResult = (res, ex) -> {
135137
System.out.println("Returned ok - " + res);
136138
System.out.println("ID Token - " + res.idToken());
137139

138-
/* call a protected API with res.accessToken() */
140+
/* Call a protected API with res.accessToken() */
139141
};
140142

141143
future.whenCompleteAsync(processAuthResult);
@@ -146,12 +148,12 @@ future.join();
146148

147149
### Protocol
148150

149-
If you don't have yet a library for your language of choice, you might want to use the protocol directly:
151+
If you don't yet have a library for your chosen language, you might want to use the protocol directly:
150152

151-
#### First case: Access token request with a shared secret
153+
#### First case: Access the token request by using a shared secret
152154

153155
```Text
154-
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 //Line breaks for clarity
156+
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 //Line breaks for clarity.
155157
Host: login.microsoftonline.com
156158
Content-Type: application/x-www-form-urlencoded
157159
@@ -161,10 +163,10 @@ client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
161163
&grant_type=client_credentials
162164
```
163165

164-
#### Second case: Access token request with a certificate
166+
#### Second case: Access the token request by using a certificate
165167

166168
```Text
167-
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 // Line breaks for clarity
169+
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 // Line breaks for clarity.
168170
Host: login.microsoftonline.com
169171
Content-Type: application/x-www-form-urlencoded
170172
@@ -179,8 +181,8 @@ For more information, see the protocol documentation: [Microsoft identity platfo
179181

180182
## Application token cache
181183

182-
In MSAL.NET, `AcquireTokenForClient` uses the **application token cache** (All the other AcquireTokenXX methods use the user token cache)
183-
Don't call `AcquireTokenSilent` before calling `AcquireTokenForClient` as `AcquireTokenSilent` uses the **user** token cache. `AcquireTokenForClient` checks the **application** token cache itself and updates it.
184+
In MSAL.NET, `AcquireTokenForClient` uses the application token cache. (All the other AcquireToken*XX* methods use the user token cache.)
185+
Don't call `AcquireTokenSilent` before you call `AcquireTokenForClient`, because `AcquireTokenSilent` uses the *user* token cache. `AcquireTokenForClient` checks the *application* token cache itself and updates it.
184186

185187
## Troubleshooting
186188

@@ -190,8 +192,8 @@ If you get an error message telling you that you used an invalid scope, you prob
190192

191193
### Did you forget to provide admin consent? Daemon apps need it!
192194

193-
If you get an error when calling the API **Insufficient privileges to complete the operation**, the tenant administrator needs to grant permissions to the application. See step 6 of Register the client app above.
194-
You'll typically see and error like the following error description:
195+
If you get an **Insufficient privileges to complete the operation** error when you call the API, the tenant administrator needs to grant permissions to the application. See step 6 of Register the client app above.
196+
You'll typically see an error that looks like this error:
195197

196198
```JSon
197199
Failed to call the web API: Forbidden

0 commit comments

Comments
 (0)