Skip to content

Commit 7dd7344

Browse files
committed
Updating the other articles for daemon
1 parent 004b953 commit 7dd7344

File tree

2 files changed

+131
-39
lines changed

2 files changed

+131
-39
lines changed

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

Lines changed: 77 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,23 @@ After you've constructed a confidential client application, you can acquire a to
2222

2323
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.
2424

25-
# [.NET](#tab/dotnet)
25+
# [.NET](#tab/idweb)
2626

27-
```csharp
28-
ResourceId = "someAppIDURI";
29-
var scopes = new [] { ResourceId+"/.default"};
27+
Here's an example of defining the scopes for the web API as part of the configuration in an [*appsettings.json*](https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/blob/master/2-Call-OwnApi/daemon-console/appsettings.json) file. This example is taken from the [.NET Core console daemon](https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2) code sample on GitHub.
28+
29+
```json
30+
{
31+
"AzureAd": {
32+
// Same AzureAd section as before.
33+
},
34+
35+
"MyWebApi": {
36+
"BaseUrl": "https://localhost:44372/",
37+
"RelativePath": "api/TodoList",
38+
"RequestAppToken": true,
39+
"Scopes": [ "[Enter here the scopes for your web API]" ]
40+
}
41+
}
3042
```
3143

3244
# [Java](#tab/java)
@@ -53,6 +65,13 @@ In MSAL Python, the configuration file looks like this code snippet:
5365
}
5466
```
5567

68+
# [.NET (low level)](#tab/dotnet)
69+
70+
```csharp
71+
ResourceId = "someAppIDURI";
72+
var scopes = new [] { ResourceId+"/.default"};
73+
```
74+
5675
---
5776

5877
### Azure AD (v1.0) resources
@@ -65,41 +84,29 @@ The scope used for client credentials should always be the resource ID followed
6584
6685
## AcquireTokenForClient API
6786

68-
To acquire a token for the app, you'll use `AcquireTokenForClient` or its equivalent, depending on the platform.
87+
To acquire a token for the app, use `AcquireTokenForClient` or its equivalent, depending on the platform.
6988

70-
# [.NET](#tab/dotnet)
89+
# [.NET](#tab/idweb)
90+
91+
With Microsoft.Identity.Web, you don't need to acquire a token. You can use higher level APIs, as you see in [Calling a web API from a daemon application](scenario-daemon-call-api.md). If however you're using an SDK that requires a token, the following code snippet shows how to get this token.
7192

7293
```csharp
73-
using Microsoft.Identity.Client;
94+
using Microsoft.Extensions.DependencyInjection;
95+
using Microsoft.Identity.Abstractions;
96+
using Microsoft.Identity.Web;
7497

75-
// With client credentials flows, the scope is always of the shape "resource/.default" because the
76-
// application permissions need to be set statically (in the portal or by PowerShell), and then granted by
77-
// a tenant administrator.
78-
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
98+
// In the Program.cs, acquire a token for your downstream API
7999
80-
AuthenticationResult result = null;
81-
try
82-
{
83-
result = await app.AcquireTokenForClient(scopes)
84-
.ExecuteAsync();
85-
}
86-
catch (MsalUiRequiredException ex)
87-
{
88-
// The application doesn't have sufficient permissions.
89-
// - Did you declare enough app permissions during app creation?
90-
// - Did the tenant admin grant permissions to the application?
91-
}
92-
catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
93-
{
94-
// Invalid scope. The scope has to be in the form "https://resourceurl/.default"
95-
// Mitigation: Change the scope to be as expected.
96-
}
100+
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
101+
ITokenAcquirer acquirer = tokenAcquirerFactory.GetTokenAcquirer();
102+
AcquireTokenResult tokenResult = await acquirer.GetTokenForUserAsync(new[] { https://graph.microsoft.com/.default" });
103+
string accessToken = tokenResult.AccessToken;
97104
```
98105

99106
### AcquireTokenForClient uses the application token cache
100107

101108
In MSAL.NET, `AcquireTokenForClient` uses the application token cache. (All the other AcquireToken*XX* methods use the user token cache.)
102-
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.
109+
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.
103110

104111
# [Java](#tab/java)
105112

@@ -152,7 +159,7 @@ private static IAuthenticationResult acquireToken() throws Exception {
152159

153160
# [Node.js](#tab/nodejs)
154161

155-
The code snippet below illustrates token acquisition in an MSAL Node confidential client application:
162+
The following code snippet illustrates token acquisition in an MSAL Node confidential client application:
156163

157164
```JavaScript
158165
try {
@@ -187,6 +194,40 @@ else:
187194
print(result.get("correlation_id")) # You might need this when reporting a bug.
188195
```
189196

197+
# [.NET (low level)](#tab/dotnet)
198+
199+
```csharp
200+
using Microsoft.Identity.Client;
201+
202+
// With client credentials flows, the scope is always of the shape "resource/.default" because the
203+
// application permissions need to be set statically (in the portal or by PowerShell), and then granted by
204+
// a tenant administrator.
205+
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
206+
207+
AuthenticationResult result = null;
208+
try
209+
{
210+
result = await app.AcquireTokenForClient(scopes)
211+
.ExecuteAsync();
212+
}
213+
catch (MsalUiRequiredException ex)
214+
{
215+
// The application doesn't have sufficient permissions.
216+
// - Did you declare enough app permissions during app creation?
217+
// - Did the tenant admin grant permissions to the application?
218+
}
219+
catch (MsalServiceException ex) when (ex.Message.Contains("AADSTS70011"))
220+
{
221+
// Invalid scope. The scope has to be in the form "https://resourceurl/.default"
222+
// Mitigation: Change the scope to be as expected.
223+
}
224+
```
225+
226+
### AcquireTokenForClient uses the application token cache
227+
228+
In MSAL.NET, `AcquireTokenForClient` uses the application token cache. (All the other AcquireToken*XX* methods use the user token cache.)
229+
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.
230+
190231
---
191232

192233
### Protocol
@@ -253,10 +294,10 @@ If your daemon app calls your own web API and you weren't able to add an app per
253294

254295
## Next steps
255296

256-
# [.NET](#tab/dotnet)
297+
# [.NET](#tab/idweb)
257298

258299
Move on to the next article in this scenario,
259-
[Calling a web API](./scenario-daemon-call-api.md?tabs=dotnet).
300+
[Calling a web API](./scenario-daemon-call-api.md?tabs=idweb).
260301

261302
# [Java](#tab/java)
262303

@@ -273,4 +314,8 @@ Move on to the next article in this scenario,
273314
Move on to the next article in this scenario,
274315
[Calling a web API](./scenario-daemon-call-api.md?tabs=python).
275316

317+
# [.NET low level](#tab/dotnet)
318+
319+
Move on to the next article in this scenario,
320+
[Calling a web API](./scenario-daemon-call-api.md?tabs=dotnet).
276321
---

articles/active-directory/develop/scenario-daemon-call-api.md

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,53 @@ ms.custom: aaddev
2020

2121
# Daemon app that calls web APIs - call a web API from the app
2222

23-
.NET daemon apps can call a web API. .NET daemon apps can also call several pre-approved web APIs.
23+
.NET daemon apps can call a web API. .NET daemon apps can also call several preapproved web APIs.
2424

2525
## Calling a web API from a daemon application
2626

2727
Here's how to use the token to call an API:
2828

29-
# [.NET](#tab/dotnet)
29+
# [.NET](#tab/idweb)
3030

31-
[!INCLUDE [Call web API in .NET](../../../includes/active-directory-develop-scenarios-call-apis-dotnet.md)]
31+
Microsoft.Identity.Web abstracts away the complexity of MSAL.NET. It provides you with higher-level APIs that handle the internals of MSAL.NET for you, such as processing Conditional Access errors, caching.
32+
33+
Here's the Program.cs of the daemon app calling a downstream API:
34+
35+
```csharp
36+
using Microsoft.Extensions.DependencyInjection;
37+
using Microsoft.Identity.Abstractions;
38+
using Microsoft.Identity.Web;
39+
40+
// In the Program.cs, acquire a token for your downstream API
41+
42+
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
43+
tokenAcquirerFactory.Services.AddDownstreamApi("MyApi",
44+
tokenAcquirerFactory.Configuration.GetSection("MyWebApi"));
45+
var sp = tokenAcquirerFactory.Build();
46+
47+
var api = sp.GetRequiredService<IDownstreamApi>();
48+
var result = await api.GetForAppAsync<IEnumerable<TodoItem>>("MyApi");
49+
Console.WriteLine($"result = {result?.Count()}");
50+
```
51+
52+
Here's the Program.cs of a daemon app that calls Microsoft Graph:
53+
54+
```csharp
55+
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
56+
tokenAcquirerFactory.Services.AddMicrosoftGraph();
57+
var serviceProvider = tokenAcquirerFactory.Build();
58+
try
59+
{
60+
GraphServiceClient graphServiceClient = serviceProvider.GetRequiredService<GraphServiceClient>();
61+
var users = await graphServiceClient.Users
62+
.Request()
63+
.WithAppOnly()
64+
.GetAsync();
65+
Console.WriteLine($"{users.Count} users");
66+
Console.ReadKey();
67+
}
68+
catch (Exception ex) { Console.WriteLine("We could not retrieve the user's list: " + $"{ex}"); }
69+
```
3270

3371
# [Java](#tab/java)
3472

@@ -86,18 +124,22 @@ http_headers = {'Authorization': 'Bearer ' + result['access_token'],
86124
data = requests.get(endpoint, headers=http_headers, stream=False).json()
87125
```
88126

127+
# [.NET low level](#tab/dotnet)
128+
129+
[!INCLUDE [Call web API in .NET](../../../includes/active-directory-develop-scenarios-call-apis-dotnet.md)]
130+
89131
---
90132

91133
## Calling several APIs
92134

93-
For daemon apps, the web APIs that you call need to be pre-approved. There's no incremental consent with daemon apps. (There's no user interaction.) The tenant admin needs to provide consent in advance for the application and all the API permissions. If you want to call several APIs, acquire a token for each resource, each time calling `AcquireTokenForClient`. MSAL will use the application token cache to avoid unnecessary service calls.
135+
For daemon apps, the web APIs that you call need to be preapproved. There's no incremental consent with daemon apps. (There's no user interaction.) The tenant admin needs to provide consent in advance for the application and all the API permissions. If you want to call several APIs, acquire a token for each resource, each time calling `AcquireTokenForClient`. MSAL uses the application token cache to avoid unnecessary service calls.
94136

95137
## Next steps
96138

97-
# [.NET](#tab/dotnet)
139+
# [.NET](#tab/idweb)
98140

99141
Move on to the next article in this scenario,
100-
[Move to production](./scenario-daemon-production.md?tabs=dotnet).
142+
[Move to production](./scenario-daemon-production.md?tabs=idweb).
101143

102144
# [Java](#tab/java)
103145

@@ -114,4 +156,9 @@ Move on to the next article in this scenario,
114156
Move on to the next article in this scenario,
115157
[Move to production](./scenario-daemon-production.md?tabs=python).
116158

117-
---
159+
# [.NET low level](#tab/dotnet)
160+
161+
Move on to the next article in this scenario,
162+
[Move to production](./scenario-daemon-production.md?tabs=dotnet).
163+
164+
---

0 commit comments

Comments
 (0)