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 (7)

  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.

Skip to main content