Skip to content

Commit 004b953

Browse files
committed
Daemon using idweb. App config
1 parent 321a331 commit 004b953

File tree

1 file changed

+182
-71
lines changed

1 file changed

+182
-71
lines changed

articles/active-directory/develop/scenario-daemon-app-configuration.md

Lines changed: 182 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ The following Microsoft libraries support daemon apps:
2828

2929
## Configure the authority
3030

31-
Daemon applications use application permissions rather than delegated permissions. So their supported account type can't be an account in any organizational directory or any personal Microsoft account (for example, Skype, Xbox, Outlook.com). There's no tenant admin to grant consent to a daemon application for a Microsoft personal account. You'll need to choose *accounts in my organization* or *accounts in any organization*.
31+
Daemon applications use application permissions rather than delegated permissions. So their supported account type can't be an account in any organizational directory or any personal Microsoft account (for example, Skype, Xbox, Outlook.com). There's no tenant admin to grant consent to a daemon application for a Microsoft personal account. You need to choose *accounts in my organization* or *accounts in any organization*.
3232

3333
The authority specified in the application configuration should be tenanted (specifying a tenant ID or a domain name associated with your organization).
3434

35-
Even if you want to provide a multitenant tool, you should use a tenant ID or domain name, and **not** `common` or `organizations` with this flow, because the service cannot reliably infer which tenant should be used.
35+
Even if you want to provide a multitenant tool, you should use a tenant ID or domain name, and **not** `common` or `organizations` with this flow, because the service can't reliably infer which tenant should be used.
3636

3737
## Configure and instantiate the application
3838

@@ -49,21 +49,28 @@ The configuration file defines:
4949
- The client ID that you got from the application registration.
5050
- Either a client secret or a certificate.
5151

52-
# [.NET](#tab/dotnet)
52+
# [.NET](#tab/idweb)
5353

54-
Here's an example of defining the configuration in an [*appsettings.json*](https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/blob/master/1-Call-MSGraph/daemon-console/appsettings.json) file. This example is taken from from the [.NET Core console daemon](https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2) code sample on GitHub.
54+
Here's an example of defining the configuration in an [*appsettings.json*](https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/blob/master/1-Call-MSGraph/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.
5555

5656
```json
5757
{
58-
"Instance": "https://login.microsoftonline.com/{0}",
59-
"Tenant": "[Enter here the tenantID or domain name for your Azure AD tenant]",
60-
"ClientId": "[Enter here the ClientId for your application]",
61-
"ClientSecret": "[Enter here a client secret for your application]",
62-
"CertificateName": "[Or instead of client secret: Enter here the name of a certificate (from the user cert store) as registered with your application]"
58+
"AzureAd": {
59+
"Instance": "https://login.microsoftonline.com/",
60+
"TenantId": "[Enter here the tenantID or domain name for your Azure AD tenant]",
61+
"ClientId": "[Enter here the ClientId for your application]",
62+
"ClientCredentials": [
63+
{
64+
"SourceType": "ClientSecret",
65+
"ClientSecret": "[Enter here a client secret for your application]"
66+
}
67+
]
68+
}
6369
}
70+
6471
```
6572

66-
You provide either a `ClientSecret` or a `CertificateName`. These settings are exclusive.
73+
You provide a certificate instead of the client secret, or [workload identity federation](/azure/active-directory/workload-identities/workload-identity-federation.md) credentials.
6774

6875
# [Java](#tab/java)
6976

@@ -123,6 +130,22 @@ When you build a confidential client with certificates, the [parameters.json](ht
123130
}
124131
```
125132

133+
# [.NET (low level) ](#tab/dotnet)
134+
135+
Here's an example of defining the configuration in an [*appsettings.json*](https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/blob/master/1-Call-MSGraph/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.
136+
137+
```json
138+
{
139+
"Instance": "https://login.microsoftonline.com/{0}",
140+
"Tenant": "[Enter here the tenantID or domain name for your Azure AD tenant]",
141+
"ClientId": "[Enter here the ClientId for your application]",
142+
"ClientSecret": "[Enter here a client secret for your application]",
143+
"CertificateName": "[Or instead of client secret: Enter here the name of a certificate (from the user cert store) as registered with your application]"
144+
}
145+
```
146+
147+
You provide either a `ClientSecret` or a `CertificateName`. These settings are exclusive.
148+
126149
---
127150

128151
### Instantiate the MSAL application
@@ -135,15 +158,38 @@ The construction is different, depending on whether you're using client secrets
135158

136159
Reference the MSAL package in your application code.
137160

138-
# [.NET](#tab/dotnet)
161+
# [.NET](#tab/idweb)
139162

140-
Add the [Microsoft.Identity.Client](https://www.nuget.org/packages/Microsoft.Identity.Client) NuGet package to your application, and then add a `using` directive in your code to reference it.
163+
Add the [Microsoft.Identity.Web.TokenAcquisition](https://www.nuget.org/packages/Microsoft.Identity.Web.TokenAcquisition) NuGet package to your application.
164+
Alternatively, if you want to call Microsoft Graph, add the [Microsoft.Identity.Web.MicrosoftGraph](https://www.nuget.org/packages/Microsoft.Identity.Web.MicrosoftGraph) package.
165+
Your project could be as follows. The *appsettings.json* file needs to be copied to the output directory.
141166

142-
In MSAL.NET, the confidential client application is represented by the `IConfidentialClientApplication` interface.
167+
```xml
168+
<Project Sdk="Microsoft.NET.Sdk">
169+
170+
<PropertyGroup>
171+
<OutputType>Exe</OutputType>
172+
<TargetFramework>net7.0</TargetFramework>
173+
<RootNamespace>daemon_console</RootNamespace>
174+
</PropertyGroup>
175+
176+
<ItemGroup>
177+
<PackageReference Include="Microsoft.Identity.Web.MicrosoftGraph" Version="2.6.1" />
178+
</ItemGroup>
179+
180+
<ItemGroup>
181+
<None Update="appsettings.json">
182+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
183+
</None>
184+
</ItemGroup>
185+
</Project>
186+
```
187+
188+
In the Program.cs file, add a `using` directive in your code to reference Microsoft.Identity.Web.
143189

144190
```csharp
145-
using Microsoft.Identity.Client;
146-
IConfidentialClientApplication app;
191+
using Microsoft.Identity.Abstractions;
192+
using Microsoft.Identity.Web;
147193
```
148194

149195
# [Java](#tab/java)
@@ -160,7 +206,7 @@ import com.microsoft.aad.msal4j.SilentParameters;
160206

161207
# [Node.js](#tab/nodejs)
162208

163-
Simply install the packages by running `npm install` in the folder where *package.json* file resides. Then, import **msal-node** package:
209+
Install the packages by running `npm install` in the folder where *package.json* file resides. Then, import **msal-node** package:
164210

165211
```JavaScript
166212
const msal = require('@azure/msal-node');
@@ -175,38 +221,52 @@ import sys
175221
import logging
176222
```
177223

178-
---
224+
# [.NET (low level)](#tab/dotnet)
179225

180-
#### Instantiate the confidential client application with a client secret
181-
182-
Here's the code to instantiate the confidential client application with a client secret:
226+
Add the [Microsoft.Identity.Client](https://www.nuget.org/packages/Microsoft.Identity.Client) NuGet package to your application, and then add a `using` directive in your code to reference it.
183227

184-
# [.NET](#tab/dotnet)
228+
In MSAL.NET, the confidential client application is represented by the `IConfidentialClientApplication` interface.
185229

186230
```csharp
187-
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
188-
.WithClientSecret(config.ClientSecret)
189-
.WithAuthority(new Uri(config.Authority))
190-
.Build();
231+
using Microsoft.Identity.Client;
232+
IConfidentialClientApplication app;
191233
```
192234

193-
The `Authority` is a concatenation of the cloud instance and the tenant ID, for example `https://login.microsoftonline.com/contoso.onmicrosoft.com` or `https://login.microsoftonline.com/eb1ed152-0000-0000-0000-32401f3f9abd`. In the *appsettings.json* file shown in the [Configuration file](#configuration-file) section, these are represented by the `Instance` and `Tenant` values, respectively.
235+
---
194236

195-
In the code sample the previous snippet was taken from, `Authority` is a property on the [AuthenticationConfig](https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/blob/ffc4a9f5d9bdba5303e98a1af34232b434075ac7/1-Call-MSGraph/daemon-console/AuthenticationConfig.cs#L61-L70) class, and is defined as such:
237+
#### Instantiate the confidential client application with a client secret
238+
239+
Here's the code to instantiate the confidential client application with a client secret:
240+
241+
# [.NET](#tab/idweb)
196242

197243
```csharp
198-
/// <summary>
199-
/// URL of the authority
200-
/// </summary>
201-
public string Authority
202-
{
203-
get
244+
class Program
204245
{
205-
return String.Format(CultureInfo.InvariantCulture, Instance, Tenant);
246+
static async Task Main(string[] _)
247+
{
248+
// Get the Token acquirer factory instance. By default it reads an appsettings.json
249+
// file if it exists in the same folder as the app (make sure that the
250+
// "Copy to Output Directory" property of the appsettings.json file is "Copy if newer").
251+
TokenAcquirerFactory tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
252+
253+
// Configure the application options to be read from the configuration
254+
// and add the services you need (Graph, token cache)
255+
IServiceCollection services = tokenAcquirerFactory.Services;
256+
services.AddMicrosoftGraph();
257+
// By default, you get an in-memory token cache.
258+
// For more token cache serialization options, see https://aka.ms/msal-net-token-cache-serialization
259+
260+
// Resolve the dependency injection.
261+
var serviceProvider = tokenAcquirerFactory.Build();
262+
263+
// ...
264+
}
206265
}
207-
}
208266
```
209267

268+
The configuration is read from the *appsettings.json*:
269+
210270
# [Java](#tab/java)
211271

212272
```Java
@@ -258,20 +318,51 @@ app = msal.ConfidentialClientApplication(
258318
)
259319
```
260320

321+
# [.NET (low level)](#tab/dotnet)
322+
323+
```csharp
324+
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
325+
.WithClientSecret(config.ClientSecret)
326+
.WithAuthority(new Uri(config.Authority))
327+
.Build();
328+
```
329+
330+
The `Authority` is a concatenation of the cloud instance and the tenant ID, for example `https://login.microsoftonline.com/contoso.onmicrosoft.com` or `https://login.microsoftonline.com/eb1ed152-0000-0000-0000-32401f3f9abd`. In the *appsettings.json* file shown in the [Configuration file](#configuration-file) section, instance and tenant are represented by the `Instance` and `Tenant` values, respectively.
331+
332+
In the code sample the previous snippet was taken from, `Authority` is a property on the [AuthenticationConfig](https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/blob/ffc4a9f5d9bdba5303e98a1af34232b434075ac7/1-Call-MSGraph/daemon-console/AuthenticationConfig.cs#L61-L70) class, and is defined as such:
333+
334+
```csharp
335+
/// <summary>
336+
/// URL of the authority
337+
/// </summary>
338+
public string Authority
339+
{
340+
get
341+
{
342+
return String.Format(CultureInfo.InvariantCulture, Instance, Tenant);
343+
}
344+
}
345+
```
346+
261347
---
262348

263349
#### Instantiate the confidential client application with a client certificate
264350

265351
Here's the code to build an application with a certificate:
266352

267-
# [.NET](#tab/dotnet)
353+
# [.NET](#tab/idweb)
268354

269-
```csharp
270-
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
271-
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
272-
.WithCertificate(certificate)
273-
.WithAuthority(new Uri(config.Authority))
274-
.Build();
355+
The code itself is exactly the same. The certificate is described in the configuration.
356+
There are many ways to get the certificate. For details see https://aka.ms/ms-id-web-certificates.
357+
Here's how you would do to get your certificate from KeyVault. Microsoft identity delegates to Azure Identity's DefaultAzureCredential, and used Managed identity when available to access the certificate from KeyVault. You can debug your application locally as it, then, uses your developer credentials.
358+
359+
```json
360+
"ClientCredentials": [
361+
{
362+
"SourceType": "KeyVault",
363+
"KeyVaultUrl": "https://yourKeyVaultUrl.vault.azure.net",
364+
"KeyVaultCertificateName": "NameOfYourCertificate"
365+
}
275366
```
276367

277368
# [Java](#tab/java)
@@ -344,42 +435,24 @@ app = msal.ConfidentialClientApplication(
344435
)
345436
```
346437

347-
---
348-
349-
#### Advanced scenario: Instantiate the confidential client application with client assertions
350-
351438
# [.NET](#tab/dotnet)
352439

353-
Instead of a client secret or a certificate, the confidential client application can also prove its identity by using client assertions.
354-
355-
MSAL.NET has two methods to provide signed assertions to the confidential client app:
356-
357-
- `.WithClientAssertion()`
358-
- `.WithClientClaims()`
359-
360-
When you use `WithClientAssertion`, provide a signed JWT. This advanced scenario is detailed in [Client assertions](msal-net-client-assertions.md).
361-
362440
```csharp
363-
string signedClientAssertion = ComputeAssertion();
441+
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
364442
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
365-
.WithClientAssertion(signedClientAssertion)
366-
.Build();
443+
.WithCertificate(certificate)
444+
.WithAuthority(new Uri(config.Authority))
445+
.Build();
367446
```
368447

369-
When you use `WithClientClaims`, MSAL.NET will produce a signed assertion that contains the claims expected by Azure AD, plus additional client claims that you want to send.
370-
This code shows how to do that:
448+
---
371449

372-
```csharp
373-
string ipAddress = "192.168.1.2";
374-
var claims = new Dictionary<string, string> { { "client_ip", ipAddress } };
375-
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
376-
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
377-
.WithAuthority(new Uri(config.Authority))
378-
.WithClientClaims(certificate, claims)
379-
.Build();
380-
```
450+
#### Advanced scenario: Instantiate the confidential client application with client assertions
381451

382-
Again, for details, see [Client assertions](msal-net-client-assertions.md).
452+
# [.NET](#tab/idweb)
453+
454+
Instead of a client secret or a certificate, the confidential client application can also prove its identity by using client assertions. See
455+
[CredentialDescription](/dotnet/api/microsoft.identity.abstractions.credentialdescription?view=msal-model-dotnet-latest) for details.
383456

384457
# [Java](#tab/java)
385458

@@ -429,11 +502,44 @@ app = msal.ConfidentialClientApplication(
429502

430503
For details, see the MSAL Python reference documentation for [ConfidentialClientApplication](https://msal-python.readthedocs.io/en/latest/#msal.ClientApplication.__init__).
431504

505+
# [.NET (low level)](#tab/dotnet)
506+
507+
Instead of a client secret or a certificate, the confidential client application can also prove its identity by using client assertions.
508+
509+
MSAL.NET has two methods to provide signed assertions to the confidential client app:
510+
511+
- `.WithClientAssertion()`
512+
- `.WithClientClaims()`
513+
514+
When you use `WithClientAssertion`, provide a signed JWT. This advanced scenario is detailed in [Client assertions](msal-net-client-assertions.md).
515+
516+
```csharp
517+
string signedClientAssertion = ComputeAssertion();
518+
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
519+
.WithClientAssertion(signedClientAssertion)
520+
.Build();
521+
```
522+
523+
When you use `WithClientClaims`, MSAL.NET produces a signed assertion that contains the claims expected by Azure AD, plus additional client claims that you want to send.
524+
This code shows how to do that:
525+
526+
```csharp
527+
string ipAddress = "192.168.1.2";
528+
var claims = new Dictionary<string, string> { { "client_ip", ipAddress } };
529+
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
530+
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
531+
.WithAuthority(new Uri(config.Authority))
532+
.WithClientClaims(certificate, claims)
533+
.Build();
534+
```
535+
536+
Again, for details, see [Client assertions](msal-net-client-assertions.md).
537+
432538
---
433539

434540
## Next steps
435541

436-
# [.NET](#tab/dotnet)
542+
# [.NET](#tab/idweb)
437543

438544
Move on to the next article in this scenario,
439545
[Acquire a token for the app](./scenario-daemon-acquire-token.md?tabs=dotnet).
@@ -453,4 +559,9 @@ Move on to the next article in this scenario,
453559
Move on to the next article in this scenario,
454560
[Acquire a token for the app](./scenario-daemon-acquire-token.md?tabs=python).
455561

562+
# [.NET (low level)](#tab/dotnet)
563+
564+
Move on to the next article in this scenario,
565+
[Acquire a token for the app](./scenario-daemon-acquire-token.md?tabs=dotnet).
566+
456567
---

0 commit comments

Comments
 (0)