Why won't my Azure AD application allow an oauth client_credentials grant?
I want to use the Azure Graph API, but first I need an oauth token. To get the token, I am trying to use Microsoft.IdentityModel.Clients.ActiveDirectory aka ADAL version 1.0.3 (from NuGet).
I'm using the overload of AuthenticationContext.AcquireToken that takes a ClientCredential object. (I can't use the overload that prompts the user to login because I'm writing a service, not an app.)
I configured my Azure AD web application as described in various tutorials/samples (e.g. ADAL - Server to Server Authentication).
My code looks like:
AuthenticationContext ac = new AuthenticationContext("https://login.windows.net/thommmondago.onmicrosoft.com");
ClientCredential cc = new ClientCredential("41151135-61b8-40f4-aff7-8627e9eaf853", clientSecretKey);
AuthenticationResult result = ac.AcquireToken("https://graph.windows.net", cc);
The AcquireToken line throws an exception:
sts_token_request_failed: Token request to security token service failed. Check InnerException for more details
The inner exception is a WebException, and the response received looks like an oauth error:
{ "error":"invalid_client",
"error_description":"ACS50012: Authentication failed."
"error_codes":[50012],
"timestamp":"2014-03-17 12:26:19Z",
"trace_id":"a4ee6702-e07b-40f7-8248-589e49e96a8d",
"correlation_id":"b304af2e-2748-4067-99d0-2d7e55b121cd" }
Bypassing ADAL and using curl with the oauth endpoint also gives the same error.
My code works if I use the details of the Azure application that I found here:
AuthenticationContext ac = new AuthenticationContext("https://login.windows.net/graphDir1.onmicrosoft.com");
ClientCredential cc = new ClientCredential("b3b1fc59-84b8-4400-a715-ea8a7e40f4fe", "FStnXT1QON84B5o38aEmFdlNhEnYtzJ91Gg/JH/Jxiw=");
AuthenticationResult result = ac.AcquireToken("https://graph.windows.net", cc);
So it's not an error with my code. I think it's either an error with my Azure AD, or I've got the ClientCredential parameters wrong.
This turned out to be an error in Windows Azure, there was nothing wrong with my code or config.
After Microsoft fixed the problem in Azure, I had to create a new application and it started working.
Forum answer from Microsoft:
Hi,
We are seeing some errors with applications created in a several day time range, ending yesterday. We are continuing to fix up these applications but I don't have a good eta when this will be done. I'm apologize for the impact here.
Can you try creating a new application and retying the operation with the new client id?
thanks
Have a look at this link: https://azure.microsoft.com/en-gb/documentation/articles/resource-manager-net-sdk/
The latest version of Active Directory Authentication Library does not support AcquireToken method, instead you have to use AcquireTokenAsync method.
var result = await authenticationContext.AcquireTokenAsync(resource: "https://{domain}.onmicrosoft.com/{site-if applicable}", clientCredential: credential);
I was having the same issue but only running the code directly from Azure (inside an Azure Website).
I solved upgrading 'Microsoft.IdentityModel.Clients.ActiveDirectory' package to '2.6.1-alpha'
The azure version of the translator has changed things once more- the Oauth token request uses a new url and only needs your secret key, instead of all the other baggage. This page discusses it (but using PHP code): http://www.bradymoritz.com/php-code-for-bingmicrosoftazure-translator/
The key items are:
Post an empty request to https://api.cognitive.microsoft.com/sts/v1.0/issueToken
Pass it your secret key using the header "Ocp-Apim-Subscription-Key: "
Or, just use the querystring parameter: "Subscription-Key="
Then get the body of the return as the actual token- it's the whole body, not in json format.
This is a lot simpler than the method used before, but it'd definitely a pain that things have yet again changed.
Related
A native app created which is calling web api.Two apps has been created in the azure.Here is the code code for getting access token and it worked well,I am getting access token:
UserCredential uc = new UserPasswordCredential(userName, password);
result = authContext.AcquireTokenAsync(todoListResourceId,clientId,
uc).Result;
Now to access new token after the expiry of old one(1 hr) i am using the code:
AuthenticationContext authContext = new AuthenticationContext(authority);
UserAssertion userAssertion = new UserAssertion(oldToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
AuthenticationResult result = authContext.AcquireTokenAsync(todoListResourceId, clientId, userAssertion).ConfigureAwait(false).GetAwaiter().GetResult();
But I am getting Error as:"Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid".
Checked JWT token :it is correct in format can able to decode using jwt.io.
Note: client Id am using for these two code snippet are the same appId.
I know this is the exact duplication of the question asked by devangi.I cannot able to comment on that question that's why I am asking it again.
Any one can able to help me out?
Or
It will be great if any one can able to help with other ways to get token with out using user password since i need to internally generate new token without user enter password again.
For the scenario when user has authenticated on a native application, and this native application needs to call a web API. Azure AD issues a JWT access token to call the web API. If the web API needs to call another downstream web API, it can use the on-behalf-of flow to delegate the user’s identity and authenticate to the second-tier web API .
Please refer to this document for more details about On-Behalf-Of flow . You can also refer to code sample .
For the scenario when when a daemon application(Your web api) needs to call a web API without user's identity , you should use client credential flow to use its own credentials instead of impersonating a user, to authenticate when calling another web service. Code sample here is for your reference .
Please click here for explanation about above two scenarios. Your code is using Resource Owner Password Credentials Grant ,this flow has multi restrictions such as don't support 2FA and is not recommended .
If i misunderstand your requirement , please feel free to let me know .
in my Xamarin.forms project, I use ADAL (Microsoft.IdentityModel.Clients.ActiveDirectory) to authenticate on the Azure portal (Auth 1.0 endpoint). That part work great, but I need to get the security group of the user. So I use this code and passing the token received with ADAL:
HttpClient client = new HttpClient();
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me/memberOf");
message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);
HttpResponseMessage response = await client.SendAsync(message);
string responseString = await response.Content.ReadAsStringAsync();
I always got StatusCode: 401, ReasonPhrase: 'Unauthorized'.
In my azure AD app registration, I add the Graph API and these permissions:
I think I miss something. Any idea?
----- EDIT 1 ---
Here my payload. I changed it for a picture for lisibility. I don't know how to post json here
----- EDIT 2 ---
OH! I see. I think I need to understand more the Azure Login process. For now I follow an example of ADAL and Azure that let my log and use some function in my backend. So the login process use:
var authContext = new AuthenticationContext(authority); var authResult = await authContext.AcquireTokenAsync(resource, clientId, uri, platformParams);
Where authority = https://login.microsoftonline.com/mysite.com, ResourceID is my backend app ID and clientID is my native app ID. So Shawn is correct, I do not use the Graph.microsoft.com to get the token. Do we have another way to achieve all that? The need of using Graph is only to get the AD group the user has to adjust permission inside the app.
You are correct in your comment. If you add a new permission to your application, you must ask the user to re-consent to the app.
You can force re-consent through ADAL by setting the PromptBehavior to Always:
platformParams.PromptBehavior = PromptBehavior.Always
Or you can simply modify your Login URL to force it, by adding the query string:
&prompt=consent
In terms of building an app to help overcome this problem, if you think your app will be changing permissions after release, you can integrate logic which detects Unauthorized, and then sends the user to re-consent.
Another option is for your app to track changes which may require a new consent prompt, and detect when the user uses this new version of your application the first time, and asks them to consent.
In our new App Model V2, we support the concept of Incremental and Dynamic Consent, which should get rid of this problem all together for you.
I've been trying to get a Xamarin Forms app to get a token from AAD.
I've tried countless different ways of doing it and they all have problems, some are bugs, some I just haven't been able to figure out.
This link is one of the simplest examples I've come across, yet it fails because it says there's no client secret.
http://www.cloudidentity.com/blog/2015/07/22/using-adal-3-x-with-xamarin-forms/
When I add the client secret, by modifying the AuthenticationContext like so
AuthenticationContext ac = new AuthenticationContext("https://login.microsoftonline.com/common");
ClientCredential cc = new ClientCredential("------4ba8-4136-ad1c-f36be878af8a", "-----sDdG4/WZCyYU=");
AuthenticationResult result = await ac.AcquireTokenAsync("https://graph.windows.net", cc);
I get a new error saying there is no application matching graph.windows.net in my directory.
Please make sure the type of the azure ad application your register is Native Client Application , that type application are meant to run on a device and aren't trusted to maintain a secret .
The code you provide is using client credential flow to acquire token , that flow uses app's credentials instead of impersonating a user .
Going by the code provided by Microsoft (I'm assuming), I am unable to query my Azure Active Directory. Every time I call the following, I get a response of {Authorization Required.}:
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
IPagedCollection<IUser> pagedCollection = await client.Users.ExecuteAsync();
I'm new to Azure Active Directory and I'm new to the Graph and thought that the samples provided would function. They do not and I am hoping someone here can tell me either what is wrong with the code or how do I grant myself authorization to my own directory? I thought the AccessKey would be the authentication method, but apparently that's useless as it's not used in their examples.
Basically, to call the REST which protected by Azure AD which support OAuth2.0 to authorize the third-party application, we need to pass a bearer token.
And to go through the code sample, please ensure that you followed the steps list by the README.md.
Note: there is something not clear in the README.md about config the permission. The code sample is using the Azure AD Graph instead of Microsoft Graph, we need to choose the Windows Azure Active Directory instead of Microsoft Graph. And I have report this issue here.
You can see that there is a static filed named token in class AuthenticationHelper which will be set the value when the users sign-in using the code in Startup.Auth.cs like below:( not using cert)
// Create a Client Credential Using an Application Key
ClientCredential credential = new ClientCredential(clientId, appKey);
string userObjectID = context.AuthenticationTicket.Identity.FindFirst(
"http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceId);
AuthenticationHelper.token = result.AccessToken;
And here is the detail progress to acquire the token via the OAuth 2.0 code grant flow:
More detail about this flow you can refer here.
please kindly help me out with my attempt to implement client side authentication for a xamarin forms aplication i am developing. i have followed every single tutorial on how to integrate Azure active directory into xamarin when using azure mobile services. the error is always thrown at the point of calling loginAsync. on futher investigation using the azure log i found out that the error was coming from the easyauthmodule. please help like i said i have followed every single tutorial on this issue and i have been on it now everyday for the past one week
please find my code below
try
{
AuthenticationContext ac = new AuthenticationContext(authority);
ac.TokenCache.Clear();
AuthenticationResult ar = await ac.AcquireTokenAsync(resource, clientId, new Uri(returnUri), new PlatformParameters(this));
JObject payload = new JObject();
payload["access_token"] = ar.AccessToken;
// DataRepository.DefaultManager.CurrentClient.Logout();
user = await DataRepository.DefaultManager.CurrentClient.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory,payload);
}
catch (Exception ex)
{
CreateAndShowDialog(ex.Message, "Authentication failed");
}
EasyAuth is incompatible with Azure Mobile Services. Are you sure you are using the right service moniker?
Make sure you are using the following NuGet for Azure Mobile Apps: https://www.nuget.org/packages/Microsoft.Azure.Mobile.Client/
EasyAuth is only available in Azure App Service. You need to configure the App Service Authentication / Authorization module. Assuming you have already integrated ADAL into your Xamarin app and have an access token from ADAL, your code is pretty close. However, I've found that configuration of AAD for mobile apps is complex. So I wrote a couple of blog posts about it.
Here is the server flow edition: https://shellmonger.com/2016/04/04/30-days-of-zumo-v2-azure-mobile-apps-day-3-azure-ad-authentication/
Here is the client flow edition: https://shellmonger.com/2016/04/06/30-days-of-zumo-v2-azure-mobile-apps-day-4-adal-integration/
Both are using Cordova as a mobile client, but the configuration of the service is identical. The client details (aside from the obvious language differences) are similar as well.