Azure AD authentication failing when using ms live accounts other than my AAD acount - c#

I trying to read user data from their Microsoft live account. I have written code as below:
public void GetUserData(){
var authContext = new AuthenticationContext("https://login.microsoftonline.com/common/");
var result = _authenticationContext
.AcquireTokenAsync("https://graph.microsoft.com", "<my client/app ID>", "<redirect URI>", new PlatformParameters(PromptBehavior.RefreshSession))
.Result;
var accessToken = result.AccessToken;
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",accessToken);
var userResponse = httpClient.GetStringAsync("https://graph.microsoft.com/beta/me/").Result;
//DO SOMTHING WITH DATA
}
my code is working fine when I used my AAD credentials, but when I used my personal account it is giving the following error.
AADSTS50020: User account 'XXXX#outlook.com' from identity provider
'live.com' does not exist in tenant 'Default Directory' and cannot
access the application 'XXXXXXXXXXXXXXXXX' in that
tenant. The account needs to be added as an external user in the
tenant first. Sign out and sign in again with a different Azure Active
Directory user account.
Here is the screenshot:
It's similar to this question. could someone help me out?

v1 endpoints require that the user is a member in a directory.
You should probably use the v2.0 endpoints for this: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-appmodel-v2-overview
If you expect only consumer MS accounts to login, you can specify the authorize URL as:
https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize

First, for the error massage in your question, you need to add the live account into your directory first and then try to use Azure AD v2 endpoint to authenticate. You can not sign in the app with the external account which was not in that directory.
I assume that you want any Microsoft live account can use your app.
Based on this requirement, I suggest you can use Azure AD B2C to achieve this. Azure AD B2C can enables your application to authenticate with any Microsoft account. You can add Microsoft Account as a social identity providers. So that any live accounts can sign up and sign in your App through Azure AD B2C.
You can see more details about Providing sign-up and sign-in to consumers with Microsoft accounts in this official document.
Hope this helps.

Related

Not able to get all users from Azure Active Directory

I am using solution mentioned here to get all users from Active Directory however I suspect the code is pulling disabled users from our old Active Directory. The new one is Azure Active Directory. Please let me know what change is required to get below details of only active users from Azure Active Directory:
First Name
Last Name
Email
Enterprise ID
Getting all users in Azure AD can use Microsoft Graph API. Here's the API for listing users. But it doesn't support personal Microsoft account, it only supports work or school accounts. By the way, I'm not sure what is Enterprise ID, could you pls take a look at this section to check if this API contained it?
I assume you have an asp.net core WEB API which is used to getting user list. So you should use code like below.
using Microsoft.Graph;
using Azure.Identity;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenant_name.onmicrosoft.com";
var clientId = "aad_app_id";
var clientSecret = "client_secret";
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var users = await graphClient.Users.Request().GetAsync();
Then an Azure AD application is required for the variables in code above. Pls follow this document to register the Azure AD app. Since my assumption is based on a web API, no need to add redirect URL here. Now we can get tenantId , clientId in Overview blade, and created the client secret. We also need to modify API permissions blade and add required API permissions. What we need is Application permission User.Read.All,User.ReadWrite.All,Directory.Read.All, Directory.ReadWrite.All.

Exception in Azure AcquireTokenAsync() accessing_ws_metadata_exchange_failed

Regarding adding external Gmail users to the Azure Active Directory Group, I have invited a Gmail user from the azure portal and the Gmail user has granted the consent to access the Application registered in Azure Enterprise Application.
When the Gmail user tried to Sign In into my Single Sign-On page, Azure validation is throwing the exception, when I am trying to acquire token by AcquireTokenAsync() Method
accessing_ws_metadata_exchange_failed
Response status code does not indicate success: 406 (NotAcceptable).
Below is my C# code to validate the users against Azure Active Directory.
var authority = string.Format(CultureInfo.InvariantCulture, "https://login.windows.net/{0}", tenantId);
var authenticationcontext = new AuthenticationContext(authority);
var upc = new UserPasswordCredential(username, password); //gmailusername and password
authenticationResult = authenticationcontext.AcquireTokenAsync("https://graph.windows.net", clientId, upc).Result;
The login flow you are using doesn't really work well with federated users (like these Guests).
Resource Owner Password Credentials (ROPC) grant flow that you are using here is only really meant to be a legacy upgrade path and isn't really modern authentication.
By the way, that login flow also does not support users with Multi-Factor Authentication or an expired password.
You could use Authorization code flow to login(back-end web app/native app).
In the case of a back-end Web app,
authorization code flow works by you redirecting the user to login,
getting a code back which you exchange for tokens.
In native apps it can be used by showing a pop-up of the login page to the user.
It can be used through different overloads of AcquireTokenAsync().

Azure Active Directory B2C log in user with specified email address

I am using the following code to sign in the user at first time with AAD B2C using Microsoft IDP.
var localAccounts = (List<IAccount>) await AADB2C.PublicClientApp.GetAccountsAsync();
var authResult = await AADB2C.PublicClientApp.AcquireTokenInteractive(AADB2C.ApiScopes)
//.WithAccount(GetAccountByPolicy(localAccounts, AADB2C.PolicySignUpSignIn))
//.WithPrompt(Prompt.SelectAccount)
.WithLoginHint(WindowsUser.Email)
//.WithExtraQueryParameters("login_hint=" + WindowsUser.Email)
.ExecuteAsync();
I try to achieve to specify the login email address, so when the user log in the email address should be filled out at least. (Or make it readonly would be even better). For this I use the .WithLoginHint extension but it doesn't work.
Do you have any suggestion how can I solve it?
AAD B2C will be sent the login_hint param in the authorization request based off your code. Use a network trace in Chrome browser to confirm. Since there is only one IDP configured, AAD B2C redirects the user to Microsoft Account login.
AAD B2C will not pass through the login_hint parameter to the federated IdP when using the Built In user Flows, hence your observation of it "not working".
If you build this using Custom Policies, following this and this and add the following to your MS Account OIDC ClaimsProvider, B2C will pass through the login_hint using a claims resolver.
<InputClaim ClaimTypeReferenceId="prompt" DefaultValue="{OIDC:LoginHint}" />
You also need to define the claim prompt as follows:
<ClaimType Id="prompt">
<DisplayName>oidc prompt param</DisplayName>
<DataType>string</DataType>
<UserHelpText/>
</ClaimType>

Web application requiring admin consent during token retrieval

My goal is to bypass the login screen and use Azure AD as the Identity Provider.
Given I am already logged in with my Azure AD user, I'd like to retrieve the authorization token using the silent flow and use this for resources that are protected.
I have a web application running on ASP.NET MVC 5 and a user-managed and backed by Azure AD (i.e. federated user). As a starting point, I have followed the steps in this article: Integrated Windows Authentication.
If I understand correctly, I should be able to use silent authentication since my users are federated and my application is registered as a public application.
In Azure AD, my app is registered with the following properties:
The code is straightforward, from the url.
var app = PublicClientApplicationBuilder.CreateWithApplicationOptions(
new PublicClientApplicationOptions()
{
ClientId = "<clientId>",
TenantId = "<tenantId>",
LogLevel = LogLevel.Verbose,
AzureCloudInstance = AzureCloudInstance.AzurePublic,
})
.Build();
var scopes = new [] { "User.Read" };
var result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
.WithUsername("<username>")
.ExecuteAsync();
The call for acquiring the token throws the following exception:
"AADSTS65001: The user or administrator has not consented to use the application with ID 'xxx' named 'xxx'. Send an interactive authorization request for this user and resource"
Per the documentation, User.Read doesn't need Admin Consent.
So what am I doing wrong here?
EDIT:
I have constructed a URL that prompts for user consent: https://login.microsoftonline.com/tenantId/oauth2/authorize?client_id=clientId&response_type=code&redirect_uri=<myApp>&nonce=1234&resource=User.Read&prompt=consent
It takes me to the screen where I need to pick my account, and after that, I get redirected to my app, where I get the same exception again.
So it doesn't show any consent screen, just asking me to pick the Microsoft account I want to use. Is this because of consent for User.Read is already granted by the admin?
But why am I still receiving the error? I'm a bit confused at this point.
You're mixing two different AAD OAuth mechanisms (aka v1 and v2 endpoints). The v1 endpoint uses Resources (https://graph.microsoft.com) while the v2 endpoint use Scopes (user.read). So when you request resource=User.Read, you are passing it an invalid resource name.
I would recommend using the v2 endpoint with the following URI prototype (line breaks for readability):
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
?client_id={clientId}
&response_type=id_token
&redirect_uri={your_app}
&response_mode=fragment
&scope=user.read
Because Integrated Windows Authentication is a silent flow, the user of your application must have previously consented to use the application or the tenant admin must have previously consented to all users in the tenant to use the application.
You can force user consent through a URL request with prompt=consent, the url will look like:
https://login.microsoftonline.com/<tenant-id>/oauth2/authorize?client_id=<client id>&response_type=code&redirect_uri=<Your-Redirect-URI-Https-Encoded>&nonce=1234&resource=<your-resource-Https-encoded>&prompt=consent
If it needs admin consent, use $prompt=admin_consent instead.(need to use admin account to sign in)
For more details about fix error AADSTS65001, you could refer to this article.
With delegated permissions, every user will need to consent to the application. If you do not want that requirement, a tenant administrator can consent for all users from the Azure Portal.

Office 365 APIs Microsoft Graph authentication failed

I registered sample app from Microsoft graph sample app
And standard login is working but when I try to make it simplier by using this code:
var authContext = new AuthenticationContext(Settings.AzureADAuthority);
var token = authContext.AcquireToken(Settings.O365UnifiedAPIResource, new ClientCredential(Settings.ClientId, Settings.ClientSecret)).AccessToken;
I get the following error: Application with identifier '[ClientId here]' was not found in the directory microsoft.com
Setting.O365UnifiedAPIResource = #"https://graph.microsoft.com/";
Settings.AzureADAuthority = #"https://login.microsoftonline.com/common";
Does anyone know what can be the problem?
Settings.AzureADAuthority = #"https://login.microsoftonline.com/{tenant_id or tenant_name}";
When acquiring the token by using the client credential (client id + client secret). You should specify the tenant explicitly.
For example:
https://login.microsoftonline.com/{tenant_id}
or
https://login.microsoftonline.com/{your_domain.onmicrosoft.com}
BTW, as this registration will be for the sample app, it will only have the Mail.Send permission which is delegated permission. To acquire the app token, you also need to grant the app level permission in Azure AD since your are acquiring the app token rather than the user token.

Categories