EWS Authentication: OAuth with service account - oauth

I have below code and working fine when i am running the application from local machine.
But I am getting below exception while running the same application using a service account
// Configure the MSAL client to get tokens
var app = ConfidentialClientApplicationBuilder
.Create(ConfigurationManager.AppSettings["appId"])
.WithAuthority(AzureCloudInstance.AzurePublic, ConfigurationManager.AppSettings["tenantId"])
.WithClientSecret(ConfigurationManager.AppSettings["clientSecret"]).Build();
// The permission scope required for EWS access
var ewsScopes = new string[] { "https://outlook.office.com/.default" };
//Make the toekn request
AuthenticationResult authResult = await app.AcquireTokenForClient(ewsScopes).ExecuteAsync();
Exception : An error occurred while sending the request. at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task
Exception in is on
AuthenticationResult authResult = await app.AcquireTokenForClient(ewsScopes).ExecuteAsync();
Thanks in advance
Regards,
Nidheesh

Related

UnknownError issue with when querying communications/calls/{id}

I am using the following code to query the Graph API to retrieve a Team's call information. However, I constantly get the error (pasted below). I am not sure what I am missing. Any help is much appreciated.
Code:
// The client credentials flow requires that you request the
// /.default scope, and preconfigure your permissions on the
// app registration in Azure. An administrator must grant consent
// to those permissions beforehand.
string[] scopes = new[] { "https://graph.microsoft.com/.default" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
//string tenantId = "common";
string tenantId = AzureDetails.TenantID;
// Values from app registration
string clientId = AzureDetails.ClientID;
string clientSecret = AzureDetails.ClientSecret;
// using Azure.Identity;
TokenCredentialOptions options = new()
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
ClientSecretCredential clientSecretCredential = new(tenantId, clientId, clientSecret, options);
GraphServiceClient graphClient = new(clientSecretCredential, scopes);
call = await graphClient.Communications.Calls[id].Request().GetAsync();
Exception:
Code: UnknownError
Inner error:
AdditionalData:
date: 2022-08-30T17:11:46
request-id: b00e1f14-82d7-459b-bbdc-ae13ae04cdb2
client-request-id: b00e1f14-82d7-459b-bbdc-ae13ae04cdb2
ClientRequestId: b00e1f14-82d7-459b-bbdc-ae13ae04cdb2
Looks like the permission issue, These the are the permissions required for getting the communication call information:
Only application permissions are supported not delegated permissions for this API.
Please also check your token here https://jwt.ms/, if it has requested permissions.

Azure Key Vault Quickstart fails to provide key vault client

I am learning the Azure Key Vault. I am trying to follow https://learn.microsoft.com/en-us/azure/key-vault/secrets/quick-create-net. I have created a vault in the portal, assigned an access policy for a user account. I have seen the vault in the protal, and I have seen that the user has I have set the environment variable value. I use an 'az login' command at a prompt to use that account. From the prompt I run the code in the quickstart. It prompts for a secret. I enter 'bob.' It throws an exception.
"Creating a secret in [...]-key-vault called 'mySecret' with the value 'bob' ...Unhandled exception. Azure.Identity.AuthenticationFailedException: SharedTokenCacheCredential authentication failed: A configuration issue is preventing authentication - check the error message from the server for details.You can modify the configuration in the application registration portal. See https://aka.ms/msal-net-invalid-client for details. Original exception: AADSTS70002: The client does not exist or is not enabled for consumers. If you are the application developer, configure a new application through the App Registrations in the Azure Portal at https://go.microsoft.com/fwlink/?linkid=2083908."
The exception is at
await client.SetSecretAsync(secretName, secretValue);
I think the problem is coming from
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
The client is not able to send tokens that the vault accepts. I am at a loss. I have had a couple of people with some expertise in using the Vault review this code and they haven't been able to provide insight. Any help?
Here is the code, from the example:
using System;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
namespace key_vault_console_app
{
class Program
{
static async Task Main(string[] args)
{
const string secretName = "mySecret";
var keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");
var kvUri = $"https://{keyVaultName}.vault.azure.net";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
Console.Write("Input the value of your secret > ");
var secretValue = Console.ReadLine();
Console.Write($"Creating a secret in {keyVaultName} called '{secretName}' with the value '{secretValue}' ...");
await client.SetSecretAsync(secretName, secretValue);
Console.WriteLine(" done.");
Console.WriteLine("Forgetting your secret.");
secretValue = string.Empty;
Console.WriteLine($"Your secret is '{secretValue}'.");
Console.WriteLine($"Retrieving your secret from {keyVaultName}.");
var secret = await client.GetSecretAsync(secretName);
Console.WriteLine($"Your secret is '{secret.Value}'.");
Console.Write($"Deleting your secret from {keyVaultName} ...");
DeleteSecretOperation operation = await client.StartDeleteSecretAsync(secretName);
// You only need to wait for completion if you want to purge or recover the secret.
await operation.WaitForCompletionAsync();
Console.WriteLine(" done.");
Console.Write($"Purging your secret from {keyVaultName} ...");
await client.PurgeDeletedSecretAsync(secretName);
Console.WriteLine(" done.");
}
}
}
Not Sure the root reason for it. But If you want to use a user account to login to Azure and access your key vault, using UsernamePasswordCredential() could be a workaround here.
To use UsernamePasswordCredential(), you should register a client application in Azure AD: Go to Azure portal =>Azure Active Directory => New registration
Note its application ID:
Go to API permissioms, and grant key vault user_impersonation permission so that users could access key vault via this app.
Click "Grant admin consent for.." to finish the permission grant process.
Go to the "Authentication" blade, turn on "Allow public client flows" so that Azure will consider this app as a public client:
Try the code below to create a secret:
using System;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
namespace key_vault_console_app
{
class Program
{
static async Task Main(string[] args)
{
const string secretName = "mySecret2";
var keyVaultName = "<your kv name>";
var kvUri = $"https://{keyVaultName}.vault.azure.net";
var userCred = new UsernamePasswordCredential("<user account name>", "<user password>", "<your tenant name/id>", "<client application ID WHCIH we created above>");
var client = new SecretClient(new Uri(kvUri), userCred);
Console.Write("Input the value of your secret > ");
var secretValue = Console.ReadLine();
Console.Write($"Creating a secret in {keyVaultName} called '{secretName}' with the value '{secretValue}' ...");
await client.SetSecretAsync(secretName, secretValue);
Console.WriteLine(" done.");
}
}
}
Result:

MSAL + Graph AcquireTokenForClient Issue

Intermittent Issue or stops working after a while: SSL error while calling AcquireTokenForClient from .NET Core WEB API.
Works fine in Dev machine. Seeing this issue in server and not sure when it stops. IIS server is running on-prem and calling Azure AD with MSAL.
Code directly used from Microsoft Sample to connect to Graph....
app = ConfidentialClientApplicationBuilder.Create(AuthHelper.ClientId)
.WithTenantId(AuthHelper.Tenant)
.WithClientSecret(AuthHelper.ClientSecret)
.Build();
// a tenant administrator
`string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync(System.Threading.CancellationToken.None);
}
Exception:
The SSL connection could not be established, see inner exception.\nTrace
at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)

Unable to acquire tokens for multiple resources simultaneously through Azure AD

I have a web application where I am trying to acquire tokens for both Power BI and Microsoft Graph API simultaneously using the below mentioned code snippet.
AuthenticationContext authContext =
new AuthenticationContext(Authority, new NaiveSessionCache(signedInUserID));
//Getting Power BI token
AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
code,
new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)),
credential,
pbiResourceID);
//Getting Graph token
AuthenticationResult graphResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
code,
new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)),
credential,
graphResourceId);
The request for acquiring token from Graph API is failing with error:
AADSTS50079: The user is required to use multi-factor authentication

How to get access token for web api from native app in other tenant?

I've created a multi tenant Web API that works just fine. Now I want to build a native client for testing. The Web API app is defined in one tenant (webapitenant). The test app is defined in another tenant (clienttenant) that has given admin consent to the Web API.
I've added the testClientId as a knownClientApplication in the Web API's app manifest and oauth2AllowImplicitFlow enabled. The test client has been granted permissions to the Web API app.
GetAccessToken:
var userCredential = new UserCredential("admin#clienttenant.onmicrosoft.com", "password");
var context = new AuthenticationContext("https://login.windows.net/common");
return context.AcquireToken("https://webapitenant.onmicrosoft.com/webApiResourceUri", testClientId, userCredential).AccessToken;
Exception thrown: 'Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException' in Microsoft.IdentityModel.Clients.ActiveDirectory.dll
Additional information: AADSTS65001: The user or administrator has not consented to use the application with ID 'nativeclientid'. Send an interactive authorization request for this user and resource.
Exception thrown: 'Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException' in Microsoft.IdentityModel.Clients.ActiveDirectory.dll
Additional information: AADSTS65001: The user or administrator has not consented to use the application with ID nativeclientid. Send an interactive authorization request for this user and resource.
Update
I created a dummy console app to force a consent form that I could accept. ADAL now returns tokens but my Web API rejects them (status 401).
var parameters = new PlatformParameters(PromptBehavior.Always);
var context = new AuthenticationContext("https://login.windows.net/common");
var token = context.AcquireTokenAsync
("https://webapi.onmicrosoft.com/appuri",
"testappid",
new Uri("https://webapi.azurewebsites.net"), parameters).Result.AccessToken;
Console.WriteLine(token); //Output: oauth token
var client = new HttpClient
{
BaseAddress = new Uri("https://webapi.azurewebsites.net/api/")
};
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = client.GetAsync("tenants").Result;
Console.WriteLine(response.Content.ReadAsStringAsync().Result);
// Output: {"$type":"System.Web.Http.HttpError, System.Web.Http","Message":"Authorization has been denied for this request."}
Please ensure that the web app is ignore the issue validation and the audience is same as the resource(https://webapi.onmicrosoft.com/appuri",
"testappid) you acquire for the access token and this value should be the App ID URI which you can find it on old Azure portal like figure below:
Here is the relative code for setting for the authentication of multi-tenant web API:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Audience = ConfigurationManager.AppSettings["ida:Audience"],
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters= new System.IdentityModel.Tokens.TokenValidationParameters {
ValidateIssuer=false
}
});

Resources