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.
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);