I try to implement "Resource Owner Password Credentials Grant" on an Azure AD scenario.
I have a web api (DemoWebApi) and a console (DemoConsole) declared as native application.
I was able to make "Authorization Code Grant" and "Client Credentials Grant" working, but I encounter some issue with "Resource Owner Password Credentials Grant".
First I read this:
http://www.cloudidentity.com/blog/2014/07/08/using-adal-net-to-authenticate-users-via-usernamepassword/
and more especially the NO MSA section.
So I created a user in my Azure AD tenant, now I get this error message:
The user or administrator has not consented to use the application with ID 'bd274da6-80f2-458a-b74b-...'. Send an interactive authorization request for this user and resource.
I can't figure out what I should do
This is my source code:
string authority = "https://login.microsoftonline.com/7dda5ce2-2fb6-4f82-bc27-...";
AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);
UserPasswordCredential credentials = new UserPasswordCredential(login, password);
AuthenticationResult res = await authenticationContext.AcquireTokenAsync(webApiClientId, consoleClientId, credentials);
If you are using it for example as LoginController action in order to provide your customize login screen, it is worth to read one scenario which I encounter when I was working on it.
Resource Owner Password Credential flow token issued even for Incorrect Password
After one successful token allocation for correct password.
There is possibility that you need to call login controller to get access token in order to authenticate users. Now when for the first time you acquired access token by AuthenticationContext (by providing all the required information such as client id, resource id, tenant, credentials) and you again want to get access token but this time user provides a wrong password but correct client id , the Azure AD still provides the access token for the object. Wola !!!!
I have experienced this issue and I have produced this scenario 5-10 times to ensure this is actually happening.
Based on my understanding about Azure AD I reach to the conclusion that Azure AD stores access token in its TokenCache and whenever the AuthenticationContext object requests an access token it first looks for cache even before validating incoming password credentials, though it definitely looks for client id against which token has been issued. This is when things started getting interesting and you will realize how on earth they are providing the access token for the wrong password (Remember : The scenarios is first time you get access token for correct password and then next time with wrong password you still get access token when using AuthenicationContext)
Solution
If you are having the similar requirements, to resolve this possible issue you need to clear token cache of the authentication context object right after getting the AuthenticationResult from AcquireTokenAsync method.
authenticationContext.TokenCache.Clear();
and that's it :).
I guess this has never been documented and I am sure this will be helpful for anybody who is working on such requirement to design custom login page using resource owner credential flow. Although Azure strictly recommend to use other authentication flows which it provides.
You need to provide more information to help us reproduce the issue , for example , how do you register the app ,using azure portal ,powershell or visual studio.What is the user type of the new added user and how do you add that user .
Users do not have any opportunity of providing consent if username & password are passed directly. To fix that issue, you could try to grant permissions for that api in portal(better login with administrator account) :
Related
Problem: How to authenticate in MS Graph using Azure AAD access token.
Current flow:
My web app has AAD configured with "Log in with AAD"
If I log into AAD my demo app is showing and if I go to https://******.azurewebsites.net/.auth/me
then I get the access_token.
What I tried:
So I tried a couple of things and this was the last, I copied the access_token as code and tried to send it, didn't work.
I'm searching for a solution to silently use the already logged-in user and call MS Graph.
The reason for the error is that you have used the wrong code. Don't try to send the access token as a code, you should request an authorization code in your browser.
https://login.microsoftonline.com/{tenant id}/oauth2/v2.0/authorize?
client_id={client id}
&response_type=code
&redirect_uri={redirect_uri}
&response_mode=query
&scope=https://graph.microsoft.com/.default
&state=12345
In addition, redirect_uri is also a required parameter.
For the already logged in user you need follow the below steps for access:
Make sure you have enable the allow access token for the register app as below
Write code to acquire access token for the for the logged in user Reference
Now you can pass this token in other successive call to get the result.
I am using Microsoft.Identity.Claim library to conenct to azure and authenticate user.
My first idea was to use AcquireTokenByIntegratedWindowsAuth method but that requires few days until network administrator people investigate how to enable single sign-in option and change that user are now "federated" and not "managed. So I now switched to AcquireTokenInteractive method because chances are that ure will be logged in, so he will just need to choose account from automatically opened browser and that's it. No big deal.
And this works:
string clientId = "xxx";
var tenantId = "yyy";
string[] scopes = new string[] { "User.Read", "User.ReadBasic.All"};
AuthenticationResult result;
var app = PublicClientApplicationBuilder.Create(clientId)
.WithRedirectUri("http://localhost")
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId).Build();
try
{
result = await app.AcquireTokenInteractive(scopes)
.ExecuteAsync();
}
catch (MsalUiRequiredException) //see all possibl exceptions!
{
However, I don't receive claims inside token.
My idea is to send this token to server, then validate it, and if sucessfull create user in database and then use my own authenication mechanism I use for other users (that are not part of domain, completely separate user).
But I don't want all users from domain have access to this app.
So I would like to get claims, roles...
How to get claims, using this or any other lib given user email, or some other unique data?
Here I summarize all of the steps you may need to follow:
1. You need to register a app in azure ad for your service app, you can refer to this document
2. Then you need to register another app in ad as the client app, you can follow the steps in this document
3. After that, you need to do the steps in this document which I already provided in comments. Do it in the service app but not client app.
4. Then you can get the access token with your code and check the claim roles. Please note, do not add microsoft graph permissions into scopes in your code. You need to add api://<the client id of the registered app for service app>/.default into scopes.
5. Now you can find the claim roles in your access token.
Any user who logged into our system (IdentityServer as Auth) under a specific tenant should be able to create an event as an online meeting (MS Teams).
We followed Build ASP.NET Core MVC apps with Microsoft Graph and Create and enable an event as an online meeting to create an application that authenticates an AD user of an organization and allow him to create an event as an online meeting.
We are able to implement it successfully and was able to create the event as an online meeting.
But the exact scenario here is any user who is authenticated in our web application (not a AD user) should be able create a MS Teams meeting event and share it with other participants who should be able to join the meeting.
I am not sure how to achieve this.
Edit
Or at least how do I create onlineMeeting ? I tried with Client credentials provider as below
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("<<App_Id>>")
.WithTenantId("<<Tenant_Id>>")
.WithClientSecret("<<Client_Secret>>")
.Build();
ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient graphClient = new GraphServiceClient(authenticationProvider);
var onlineMeeting = new OnlineMeeting
{
StartDateTime = DateTimeOffset.Parse("2020-01-15T21:30:34.2444915+05:30"),
EndDateTime = DateTimeOffset.Parse("2020-01-15T22:00:34.2464912+05:30"),
Subject = "User Token Meeting"
};
var meeting = graphClient.Me.OnlineMeetings
.Request()
.AddAsync(onlineMeeting).Result;
but it was throwing
Code: Forbidden
Inner error:
AdditionalData:
request-id: <<some_id>>
date: 2020-07-09T16:42:23
ClientRequestId: <<some_id>>
I been working on your question in few days, I was going to mention some of the suggestions comes with the other answer. But in addition, the main challenge here, the system need to know who is authorized to do what.
So IMO The Best choice to solve this is creating a guest login in AzureAD, than you can use that to create a Team Events. Further more you can added an extra step after guest user logon, so that guest should enter his/her name and use it as reference.
You will need to take these two steps.
Get the right token
Create an event (but change the url to
https://graph.microsoft.com/v1.0/users/the_user#domain.com/events)
The hard part is getting the right token, you have multiple options.
Use the client credentials flow this will force an admin from every new tenant to authorize your application for their organization. You can then use the tenant from the user info to request a token for that tenant and use the user id to create the right url to post to.
Make IdentityServer save the access token and allow you to access it. At coonfiguration level you have access to token callback and there you can also save the Azure AD access token. I think you can add it to a reference token, that way it isn't transmitted everytime but your web application is still able to access it.
Use the on-behalf-of flow, this would require you to pass the Azure AD access token token retrieved from azure AD by the IdentityServer to be passed to your application.
Just remove the identity server from the flow and have your web application logging straight with Azure AD. That way you'll have the right token available all the time.
Edit
After reading your editted question, what you want is a website where the user doesn't have to be an member of your Azure AD, just wants access to some new online meeting?
Best option is to created a shared mailbox, authorize an application (with Calendar.ReadWrite). Get a token with client credentials and call Create Event and then extract the meeting url from the event (that you'll get back when the posts completes succesfully.
To create an online meeting for the "Client Credentials" flow, I used the following:
var confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("my-app-client-id")
.WithTenantId("my-aad-tenant-id")
.WithClientSecret("my-client-secret")
.Build();
var authProvider = new ClientCredentialProvider(confidentialClientApplication);
var graphClient = new GraphServiceClient(authProvider);
var meetingGuid = Guid.NewGuid();
var createMeetingResponse = await graphClient.Users["my-aad-user-object-id"].OnlineMeetings
.CreateOrGet(meetingGuid.ToString())
.Request()
.PostAsync();
The issue with your code is that referencing graphClient.Me causes the Graph requests to go to https://graph.microsoft.com/v1.0/me/onlineMeetings, which is not what you want in the "Client Credentials" flow. See this screenshot from the documentation found here: https://learn.microsoft.com/en-us/graph/api/onlinemeeting-createorget?view=graph-rest-1.0&tabs=csharp
I had to grant "application" permissions in Azure Portal to allow my app to access the online meetings API, and I had to create a client secret. I also had to follow this article to create a policy and grant it to specific users using Microsoft Teams PowerShell:
https://learn.microsoft.com/en-us/graph/cloud-communication-online-meeting-application-access-policy
For users not in your organization, you can invite them as a guest user to your tenant.
I had issues using the Microsoft Teams Powershell commands due to settings in Windows Remote Management, which I did something like this to work around:
https://lonesysadmin.net/2017/08/10/fix-winrm-client-issues/
I want to post an update to my own facebook page from a .NET service. I can make a FB App and that wants 'publish-actions' and 'manage_pages'. But how can I get an accessToken in code. The posts would be infrequent so I don't mind generating a new access token each time, but I need it done by the service without any interaction from me.
Following scenario 5 of https://developers.facebook.com/roadmap/offline-access-removal/ should allow you to authorize once as a user and then use the page token indefinitely without any need to re-authorize.
Exchange the short-lived user access token for a long-lived access token using the endpoint and steps explained earlier. By using a long-lived user access token, querying the [User ID]/accounts endpoint will now provide page access tokens that do not expire for pages that a user manages. This will also apply when querying with a non-expiring user access token obtained through the deprecated offline_access permission.
https://developers.facebook.com/roadmap/offline-access-removal/
I'm using dotNetOpenAuth to authorise against Google oAuth provider.
I'm a bit confused with the difference between the following:
consumerToken, consumerSecret, accessToken
From the Provider I get the accessToken for some user. Can keep I it forever? Or does it expires?
How can the code enable authorization without redirecting the user to the "allow access to my google data page" ?
Never expect have any expectations about lifespan of accessToken. At any time you can be given 403 HTTP error which should trigger on of the following in your app:
If you have a refreshToken, get a new accessToken without resource owner (end user) interaction
If not, ask user again to authorize your application
OAuth 1.0, which you're using, does not include a provision for predicting when an access token will expire, so you'll have to read Google's documentation for OAuth 1.0 access tokens to see how long they last.
How can the code enable authorization without redirecting the user to the "allow access to my google data page" ?
You don't. If you could do that, that would be a huge security leak. The user must authorize your app to access his/her data. Once you've obtained authorization once however, by storing the access token (and its secret) that you obtained you should be able to use it in the future and avoid the user authorization step (until the user revokes the token or it otherwise expires).
"AccessToken" in OAuth normally have relatively short expiration (i.e. in Facebook and Messenger case less than a day). If implementation supports it then "refreshToken" is the one you can keep longer (weeks/months range depending on provider).
According to the doc ( https://developers.google.com/accounts/docs/OAuth2 ) Google supports refresh tokens, so if you want to store token - it is the one.
Note that both accessToken and refreshToken represent very sensitive information (comparable to clear text user name and password), so please check out provider's recommendations and requirements on storing these information.