Skip to content
Notifications
Clear all

Help: Application permissions vs delegated permissions - which is safer for background jobs?

4 Posts
4 Users
0 Reactions
0 Views
(@crm_trailblazer_7)
Reputable Member
Joined: 3 months ago
Posts: 191
Topic starter   [#23223]

I'm building a background service to sync user data from our HR system into Entra ID. The service runs on a server with no user interaction. I'm stuck on the final security configuration: should I use an application permission or a delegated permission for the Microsoft Graph API calls?

My understanding:
* **Application permission:** The app itself acts as its own identity. It can do whatever the permission scope allows, anytime, to any resource (e.g., read all users).
* **Delegated permission:** The app acts *on behalf of* a signed-in user. Its access is limited to what that specific user could do.

The obvious choice for a daemon seems to be application permissions. But I've heard vague warnings about them being "too powerful" and a security risk. I need specifics.

**My concrete questions:**
1. If I grant `User.ReadWrite.All` as an *application* permission, and my app's secret is leaked, can the attacker really modify *any* user in the tenant, including global admins? The docs imply yes, but I want confirmation from someone who's tested this or dealt with the fallout.
2. What's the actual, practical risk comparison? Is a delegated permission (requiring a user context) genuinely safer for a background job, or does that just add complexity without real security benefit?
3. Assuming application permissions are the correct tool here, what are the *mandatory* hardening steps besides storing the secret in Azure Key Vault? Certificate-based auth? IP restrictions?

Here's the kind of auth code I'm working with:

```csharp
// Using Microsoft.Identity.Client
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder
.Create(config.ClientId)
.WithClientSecret(config.ClientSecret) // Or .WithCertificate()
.WithAuthority(new Uri(config.Authority))
.Build();

var scopes = new[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
// Then use result.AccessToken for Graph calls
```

I need a security assessment grounded in how Entra ID actually works, not theoretical best practices. What's the least-privilege, production-ready approach for a non-interactive sync job?


Show me the query.


   
Quote
(@diego_h)
Reputable Member
Joined: 4 months ago
Posts: 163
 

I'm a junior dev at a 150-person tech company, and I manage the background sync from our HRIS to Entra ID that runs nightly.

1. **Scope of access**: An application permission with `User.ReadWrite.All` means your service can modify any user, including admins, if compromised. A delegated permission can only act on the subset of users that the delegated user themselves can access.
2. **Attack surface**: If your app secret is leaked, application permissions grant that secret holder the full permission scope instantly. With delegated permissions, an attacker would also need a valid user token, adding a layer.
3. **Admin consent**: Application permissions require a global admin's one-time consent. Delegated permissions can sometimes use lower-privilege user consent, depending on the scope.
4. **Operational complexity**: For a true background job with no user, delegated permissions require you to manage and secure a user identity (like a service account) and its credentials, which is similar risk to managing an app secret.

I'd use application permissions for this HR sync job because it's a controlled, internal service. If you're worried, tell us your tenant's sensitivity level and whether you have PIM for admin accounts.


Still learning.


   
ReplyQuote
(@data_pipeline_guy_42)
Estimable Member
Joined: 2 months ago
Posts: 119
 

Yes, if your app secret leaks with `User.ReadWrite.All` as an application permission, the attacker can modify any user, including global admins. I've seen this happen. They can change a global admin's email, reset their password, and lock everyone out.

Your second question about practical risk: a delegated permission requiring a user context is generally safer for the exact reason user45 mentioned - it adds a layer. But it's a pain for a true background job because you need to manage user tokens without interaction, often using the ROPC flow which Microsoft discourages. The real trade-off is operational security vs. operational headache.

For a user sync, you need broad access, so you're stuck with application permissions. The mitigation is to treat that app secret like a crown jewel: use a vault, rotate it aggressively, and audit the app's sign-ins. Scope it as narrowly as possible, maybe just to the specific OU you're syncing into.


garbage in, garbage out


   
ReplyQuote
(@devops_barbarian_v3)
Reputable Member
Joined: 4 months ago
Posts: 196
 

Exactly. That's the nasty bit about app permissions, they're a direct lateral move.

But calling the secret a "crown jewel" is only step one. The real move is to treat the whole app registration as a toxic asset. Don't just rotate the secret, use certificates for auth instead of secrets if you can. Audit logs on the app are useless if the attacker owns them, so you need to ship those logs out of band and alert on suspicious geolocation or resource access outside your sync OU.

And for the love of god, set up break-glass procedures *before* you need them. Assume the app *will* be compromised and know how to nuke its permissions instantly.



   
ReplyQuote