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

  • Anonymous
    October 23, 2016
    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
    • Anonymous
      October 24, 2016
      Thank you very much for the information, just revised the post based on this.
  • Anonymous
    March 05, 2017
    when I use .net dll or http codeit 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"}
    • Anonymous
      March 07, 2017
      @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.
  • Anonymous
    March 24, 2017
    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
  • Anonymous
    March 24, 2017
    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_consentAll 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!!!
    • Anonymous
      March 24, 2017
      @Thomas, thank you to try this and provide valuable information for it.
  • Anonymous
    April 14, 2017
    Great article, the only problem with native apps is that they do not support access restrictions based on groups.
  • Anonymous
    August 17, 2017
    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
    • Anonymous
      August 18, 2017
      @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.
  • Anonymous
    November 07, 2017
    The comment has been removed
    • Anonymous
      November 08, 2017
      @Robbie, This flow doesn't support MFA. As MFA is enabled per user, you might try a user without MFA enabled.
  • Anonymous
    November 09, 2017
    Hi Wu, thank you for your answer. So if my company dont allows to create User with disabled MFA, is there the possibilty tofetch Token from pbi Service with a clientId/SecretId or other process, to show embedded PBI Report ?Thank You :-)
  • Anonymous
    December 14, 2017
    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
  • Anonymous
    September 11, 2018
    The comment has been removed
  • Anonymous
    March 04, 2019
    The comment has been removed