Resource Owner Password Credentials Grant in Azure AD OAuth


Azure AD supports varies grant flows for different scenarios, such as Authorization Code Grant for Web server application, Implicit Grant for native application, and Client Credentials Grant for service application. Furthermore, the Resource Owner Password Credentials Grant is also supported for the case that the resource owner has a trust to the target application, such as an in-house windows service.

 

As the Resource Owner Password Credentials Grant is totally based on http request without URL redirection, it not only can apply to WPF, Winform application but also C++, MFC, also no matter there is user interact or not. For more official description regarding to this flow, you may refer to RFC6749. This flow has given us much flexibility to gain a token easily, while, as this flow will expose the user name and password directly in a http request, it brings potential attack risk as well. Your credential will be lost easily if the request is sent to an unexpected endpoint, and definitely we should always avoid  handling the user credential directly. Furthermore, notice that resource owner password grant doesn't provide consent and doesn't support MFA either. So, try to use Authorization Code flow if possible and do not abuse the resource owner password grant.

The following are the parameters needed in Azure AD OAuth for resource owner password grant.

Name Description
grant_type The OAuth 2 grant type: password
resource The app to consume the token, such as Microsoft Graph, Azure AD Graph or your own Restful service
client_id The Client Id of a registered application in Azure AD
username The user account in Azure AD
password The password of the user account
scope optional, such as openid to get Id Token

 

For now, the latest .Net ADAL doesn't support this grant directly, while you can simply use the below code snippet to require access token via native http request.

using (HttpClient client = new HttpClient())
{
  var tokenEndpoint = @"https://login.windows.net/<tenant-id>/oauth2/token";
  var accept = "application/json";

  client.DefaultRequestHeaders.Add("Accept", accept);
  string postBody = @"resource=https%3A%2F%2Fgraph.microsoft.com%2F
  &client_id=<client id>
  &grant_type=password
  &username=xxx@xxx.onmicrosoft.com
  &password=<password>
  &scope=openid";

  using (var response = await client.PostAsync(tokenEndpoint, new StringContent(postBody, Encoding.UTF8, "application/x-www-form-urlencoded")))
  {
    if (response.IsSuccessStatusCode)
    {
      var jsonresult = JObject.Parse(await response.Content.ReadAsStringAsync());
      token = (string)jsonresult["access_token"];
    }
  }
}

 

And refresh token, id token as well shown below.
9-22-2016

 

For a .Net console or windows service, Owin is not available to provide token validation in middleware, you may make the validation via System.IdentityModel.Token.Jwt. This package has provided JwtSecurityTokenHandler.ValidateToken to make the validation based on a series of validation criteria such as issuer, signature; and you will be able to retrieve this information from https://login.windows.net/<tenant-id>/.well-known/openid-configuration and https://login.windows.net/common/discovery/keys

You can also use latest .Net ADAL to make the same, it is provided as extension to AuthenticationContext shown below:

public static Task<AuthenticationResult> AcquireTokenAsync(this AuthenticationContext ctx, string resource, string clientId, UserCredential userCredential);

 

Comments (15)

  1. Hi Wu,

    Thanks for your article. However, ADAL does support this grant. If you use the following piece of code:

    AuthenticationContext authenticationContext =
    new AuthenticationContext(“https://login.windows.net/ceaabb16-9554-4ac1-98bb-0e2fa69a9425/”, false);

    AuthenticationResult res = await
    authenticationContext.AcquireTokenAsync(
    “https://graph.microsoft.com/”,
    “clientid”,
    new UserPasswordCredential(“user@tenant.onmicrosoft.com”, “pwd”));

    with a native Azure AD app and examine the HTTP traffic with Fiddler, you’ll notice that the grant_type is equal to password.

    Best Regards

  2. Wu Shuai says:

    Thank you very much for the information, just revised the post based on this.

  3. Somnath says:

    when I use .net dll or http code
    it is giving
    {“error”:”invalid_client”,”error_description”:”AADSTS70002: The request body must contain the following parameter: {“error”:”invalid_client”,”error_description”:”AADSTS70002: The request body must contain the following parameter: ‘client_secret or client_assertion’.\r\nTrace ID: 943942de-6bc7-41fe-89a1-1be9e9507190\r\nCorrelation ID: a7c52be0-80b5-4d5d-b1ff-f4c86fdbf982\r\nTimestamp: 2017-03-06 06:41:33Z”,”error_codes”:[70002],”timestamp”:”2017-03-06 06:41:33Z”,”trace_id”:”943942de-6bc7-41fe-89a1-1be9e9507190″,”correlation_id”:”a7c52be0-80b5-4d5d-b1ff-f4c86fdbf982″}or client_assertion’.\r\nTrace ID: 943942de-6bc7-41fe-89a1-1be9e9507190\r\nCorrelation ID: a7c52be0-80b5-4d5d-b1ff-f4c86fdbf982\r\nTimestamp: 2017-03-06 06:41:33Z”,”error_codes”:[70002],”timestamp”:”2017-03-06 06:41:33Z”,”trace_id”:”943942de-6bc7-41fe-89a1-1be9e9507190″,”correlation_id”:”a7c52be0-80b5-4d5d-b1ff-f4c86fdbf982″}

  4. Wu Shuai says:

    @Somnath, if you register your app as a web app, then AAD will demand you send a client_secret. Please register as a native app and see the effect.

  5. Thomas says:

    Hi Wu,

    First, thank you for the wonderful write up; this has been really helpful.
    For some reason, I am finding that the latest .Net ADAL does not support UserPasswordCredential? (.Net Core)

    But, I really want the HTTP Client approach to work…do you have any suggestions for troubleshooting this error:

    {\”error\”:\”invalid_grant\”,\”error_description\”:\”AADSTS65001: The user or administrator has not consented to use the application with ID ’76ad9add-012b-4339-a66b-804e8c08a8c7′. Send an interactive authorization request for this user and resource.\\r\\nTrace ID: d84594d7-c672-4b5c-a2a9-305de7ac0b00\\r\\nCorrelation ID: e5cedca4-4f53-455d-9c4a-02f5c6d11f5d\\r\\nTimestamp: 2017-03-24 18:37:24Z\”,\”error_codes\”:[65001],\”timestamp\”:\”2017-03-24 18:37:24Z\”,\”trace_id\”:\”d84594d7-c672-4b5c-a2a9-305de7ac0b00\”,\”correlation_id\”:\”e5cedca4-4f53-455d-9c4a-02f5c6d11f5d\”}

    Many thanks in advance!
    -Thomas

  6. Thomas says:

    Hi Wu,

    After a day or two of mucking around with it, I found an answer!!! My administrator had to do the following (one time) in the browser:

    https://login.microsoftonline.com//oauth2/authorize?client_id=&response_type=code&redirect_uri&resource=https%3A%2F%2Fgraph.microsoft.com%2F&prompt=admin_consent

    All the values in the above URI had to match what was configured in Azure exactly, although the redirect_uri did not have to exist, which causes a 404 at the end of the process, but the consent still works. Note that I adjusted the Azure App permissions to include as much as possible (greedy) on Azure AD (did not want to do it twice)…and I added the Microsoft Graph permission.

    I hope this helps someone!!!

  7. Wu Shuai says:

    @Thomas, thank you to try this and provide valuable information for it.

  8. Daniel Camargo says:

    Great article, the only problem with native apps is that they do not support access restrictions based on groups.

  9. Murugadoss says:

    Hi WU,

    I registered web app in the Azure AD for authentication using user credential without Secret key but i got 401 unauthorized. I want to authenticate Azure AD without Client Secret key. please help me.

    Thanks
    Murugadoss

  10. Wu Shuai says:

    @Murugadoss, you can use implicit flow if you don’t want to use client secret. You need enable oauth2AllowImplicitFlow in the manifest file in azure ad portal.

  11. Robbie2009 says:

    Hi All,

    I work on an application c#/MVC to show PowerBi Reports embedded.

    When I running my application local on my pc (connected with VPN) I get no error and the embedded PBI Report loaded

    I call: (with my User)

    var credential = new UserCredential(Username, Password);
    authenticationResult = await authenticationContext.AcquireTokenAsync(ResourceUrl, ClientId, credential);

    (ResourceUrl = https://analysis.windows.net/powerbi/api)

    When I publish the application to Azure and running there, I got at the line

    authenticationResult = await authenticationContext.AcquireTokenAsync(ResourceUrl, ClientId, credential);

    the error

    AADSTS50076: Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication to access

    We want to use a fix/functional user for getting PBI Token (Data owns the application method)

    Is there another possibility to do it in Azure WebApp ?

    Thank you very much.

    BR

  12. Wu Shuai says:

    @Robbie, This flow doesn’t support MFA. As MFA is enabled per user, you might try a user without MFA enabled.

  13. Robbie2009 says:

    Hi Wu, thank you for your answer. So if my company dont allows to create User with disabled MFA, is there the possibilty to
    fetch Token from pbi Service with a clientId/SecretId or other process, to show embedded PBI Report ?

    Thank You 🙂

  14. Wu Shuai says:

    Hi Robbie, resource owner password credentials flow can’t help much here. Though I have not tried, client credential flow might what you want, check this https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service

  15. Sridhara says:

    Hi Wu,
    Thanks for the article, helped a lot.
    How long is the refresh token valid for and what are these fields in the response, expires_on and not_before.
    Also in the token request call I have set the scope as Mail.Read, offline_access and User.Read but in the token response I am getting some extra scope (Files.ReadWrite Mail.Read Mail.Send offline_access openid profile User.Read) where are am I getting this from.

    Thanks

Skip to main content