PPDS.Auth
1.0.0-beta.6
dotnet add package PPDS.Auth --version 1.0.0-beta.6
NuGet\Install-Package PPDS.Auth -Version 1.0.0-beta.6
<PackageReference Include="PPDS.Auth" Version="1.0.0-beta.6" />
<PackageVersion Include="PPDS.Auth" Version="1.0.0-beta.6" />
<PackageReference Include="PPDS.Auth" />
paket add PPDS.Auth --version 1.0.0-beta.6
#r "nuget: PPDS.Auth, 1.0.0-beta.6"
#:package PPDS.Auth@1.0.0-beta.6
#addin nuget:?package=PPDS.Auth&version=1.0.0-beta.6&prerelease
#tool nuget:?package=PPDS.Auth&version=1.0.0-beta.6&prerelease
PPDS.Auth
Authentication profile management for Power Platform with encrypted credential storage and multi-cloud support.
Installation
dotnet add package PPDS.Auth
Quick Start
// 1. Create and store a profile
var store = new ProfileStore();
var profile = new AuthProfile("dev")
{
AuthMethod = AuthMethod.InteractiveBrowser,
ClientId = "51f81489-12ee-4a9e-aaae-a2591f45987d" // Default Power Platform client
};
await store.SaveAsync(profile);
// 2. Authenticate and get a ServiceClient
var provider = CredentialProviderFactory.Create(profile);
var client = await ServiceClientFactory.CreateAsync(provider, profile);
Features
Profile Storage
Profiles are stored with encrypted secrets (DPAPI on Windows):
var store = new ProfileStore();
// Save a profile
await store.SaveAsync(profile);
// Load all profiles
var profiles = await store.LoadAsync();
// Get active profile
var active = profiles.GetActiveProfile();
// Set active profile
profiles.SetActive("dev");
await store.SaveAsync(profiles);
Default storage location: ~/.ppds/profiles.json
Authentication Methods
// Interactive Browser (opens browser for OAuth)
var profile = new AuthProfile("dev")
{
AuthMethod = AuthMethod.InteractiveBrowser,
ClientId = "51f81489-12ee-4a9e-aaae-a2591f45987d"
};
// Device Code (for headless/SSH environments)
var profile = new AuthProfile("dev")
{
AuthMethod = AuthMethod.DeviceCode,
ClientId = "51f81489-12ee-4a9e-aaae-a2591f45987d"
};
// Client Secret (service principal)
var profile = new AuthProfile("ci")
{
AuthMethod = AuthMethod.ClientSecret,
ApplicationId = "your-app-id",
TenantId = "your-tenant-id",
ClientSecret = "your-secret" // Stored encrypted
};
// Certificate File
var profile = new AuthProfile("prod")
{
AuthMethod = AuthMethod.CertificateFile,
ApplicationId = "your-app-id",
TenantId = "your-tenant-id",
CertificatePath = "/path/to/cert.pfx",
CertificatePassword = "password" // Stored encrypted
};
// Certificate Store (Windows)
var profile = new AuthProfile("prod")
{
AuthMethod = AuthMethod.CertificateStore,
ApplicationId = "your-app-id",
TenantId = "your-tenant-id",
CertificateThumbprint = "ABC123...",
CertificateStoreLocation = StoreLocation.CurrentUser
};
// Managed Identity (Azure-hosted)
var profile = new AuthProfile("azure")
{
AuthMethod = AuthMethod.ManagedIdentity,
ManagedIdentityClientId = "user-assigned-id" // Optional for user-assigned
};
// GitHub Actions OIDC
var profile = new AuthProfile("github")
{
AuthMethod = AuthMethod.GitHubFederated,
ApplicationId = "your-app-id",
TenantId = "your-tenant-id"
};
// Azure DevOps OIDC
var profile = new AuthProfile("azdo")
{
AuthMethod = AuthMethod.AzureDevOpsFederated,
ApplicationId = "your-app-id",
TenantId = "your-tenant-id",
AzureDevOpsServiceConnectionId = "service-connection-id"
};
Environment Discovery
Discover environments accessible to the authenticated user:
var provider = CredentialProviderFactory.Create(profile);
var discovery = new GlobalDiscoveryService();
var environments = await discovery.GetEnvironmentsAsync(provider.GetTokenAsync);
foreach (var env in environments)
{
Console.WriteLine($"{env.FriendlyName} - {env.Url}");
}
Environment Resolution
Resolve environments by various identifiers:
var resolver = new EnvironmentResolver(discovery, provider.GetTokenAsync);
// By URL
var env = await resolver.ResolveAsync("https://org.crm.dynamics.com");
// By unique name
var env = await resolver.ResolveAsync("org");
// By environment ID
var env = await resolver.ResolveAsync("00000000-0000-0000-0000-000000000000");
// By partial friendly name (fuzzy match)
var env = await resolver.ResolveAsync("Production");
Multi-Cloud Support
var profile = new AuthProfile("gcc")
{
Cloud = CloudEnvironment.UsGov, // GCC
// ... other settings
};
// Supported clouds:
// - CloudEnvironment.Public (default)
// - CloudEnvironment.UsGov (GCC)
// - CloudEnvironment.UsGovHigh (GCC High)
// - CloudEnvironment.UsGovDoD (DoD)
// - CloudEnvironment.China
// - CloudEnvironment.UsNat
// - CloudEnvironment.UsSec
Integration with PPDS.Dataverse
Use profiles as a connection source for the connection pool:
var store = new ProfileStore();
var profiles = await store.LoadAsync();
var profile = profiles.GetActiveProfile();
var provider = CredentialProviderFactory.Create(profile);
var source = new ProfileConnectionSource(profile, provider);
services.AddDataverseConnectionPool(options =>
{
options.ConnectionSources.Add(source);
});
Custom Credential Providers
Implement ICredentialProvider for custom authentication:
public class CustomCredentialProvider : ICredentialProvider
{
public string Name => "Custom";
public bool RequiresInteraction => false;
public Task<string> GetTokenAsync(string resource, CancellationToken ct)
{
// Your custom token acquisition logic
return Task.FromResult("your-token");
}
public Task<TokenInfo> GetTokenInfoAsync(CancellationToken ct)
{
return Task.FromResult(new TokenInfo
{
UserPrincipalName = "user@example.com",
TenantId = "..."
});
}
}
Security
Credential Encryption
Secrets (client secrets, passwords, etc.) are encrypted at rest:
- Windows: DPAPI (user-scoped encryption)
- Linux/macOS: Base64 encoding (use OS-level file permissions)
Token Caching
MSAL token caching is used for interactive and device code flows:
var profile = new AuthProfile("dev")
{
TokenCacheType = TokenCacheType.Persistent // Default
// TokenCacheType = TokenCacheType.InMemory // Per-process only
};
Target Frameworks
net8.0net9.0net10.0
License
MIT License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Azure.Identity (>= 1.13.2)
- Devlooped.CredentialManager (>= 2.6.1.1)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.1)
- Microsoft.Identity.Client (>= 4.81.0)
- Microsoft.Identity.Client.Extensions.Msal (>= 4.81.0)
- Microsoft.PowerPlatform.Dataverse.Client (>= 1.2.10)
- System.IdentityModel.Tokens.Jwt (>= 8.3.1)
-
net8.0
- Azure.Identity (>= 1.13.2)
- Devlooped.CredentialManager (>= 2.6.1.1)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.1)
- Microsoft.Identity.Client (>= 4.81.0)
- Microsoft.Identity.Client.Extensions.Msal (>= 4.81.0)
- Microsoft.PowerPlatform.Dataverse.Client (>= 1.2.10)
- System.IdentityModel.Tokens.Jwt (>= 8.3.1)
- System.Text.Json (>= 9.0.12)
-
net9.0
- Azure.Identity (>= 1.13.2)
- Devlooped.CredentialManager (>= 2.6.1.1)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.1)
- Microsoft.Identity.Client (>= 4.81.0)
- Microsoft.Identity.Client.Extensions.Msal (>= 4.81.0)
- Microsoft.PowerPlatform.Dataverse.Client (>= 1.2.10)
- System.IdentityModel.Tokens.Jwt (>= 8.3.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-beta.6 | 41 | 1/17/2026 |
| 1.0.0-beta.5 | 45 | 1/6/2026 |
| 1.0.0-beta.4 | 45 | 1/3/2026 |
| 1.0.0-beta.3 | 50 | 1/2/2026 |
| 1.0.0-beta.2 | 43 | 1/1/2026 |
| 1.0.0-beta.1 | 49 | 12/29/2025 |