When building Distributed Systems in Cloud or On-Prem, you will usually have to deal with token flow. That means, some application or user have to securely enter the system on some specific place. If you have distributed system if is not unusual that some applications in the system do not use authentication and some do use authentication and authorization. When user or application first time enter secured part of the system, it has to obtain security token. Cloud based application usually work with OAuth tokens.
That means, before user or service invokes some other service they need to obtain a token, from some Security Token Service. The most prominent STS in Azure is Azure Active Directory (AAD) service.
Depending if you are application (=service) or user, you might require a different token. In theory there is no any difference in physical construction of the same token. That means even user but also service can be registered as artifacts. By obtaining tokens they will both have to provide their credentials. This are commonly username and password.
But in AAD, there are few differences. For example AAD admin can set a policy, which requires a user to change the password after some time. If the user is a service, it can be required to change a password, which cannot be done, because the service has now nothing about that. It would simply stop working, because password has expired.
Another difference is that users can be asked to authenticate again after token has expired. Thi should not happen to the service. For this reason AAD provides two tokens.
- Token for services
- Token for users
Both are same OAuth JWT tokens, but they are acquired and organized a slightly different way. To acquire token for service AAD provides you so called secret key, which is typically much longer than password. By generating of the secret key admin can specify how long the key is valid like 1 year, 5 years of forever.
Users are typically authenticated by using their username and password.
How to acquire token with secret key?
If your code is running inside of a service or application, which should securely (authenticated) invoke some other service following has to be done in AAD:
1. Service which is invoking another service must be registered in AAD as application
2. Service which is invoked must also be registered in AAD as application.
3. Service, which will invoke must have delegated permission to invoke another service.
4. Service which is invoking another service must have a secret key.
To obtain the token service, which is invoking another service must provide its ClientID (newly called ApplicationId) and its key, by specifying grant_type=client_credentials.
This grant-Type signals to AAD, that secret key and clientId are provided and not username and password.
Following shows how this request should look like:
POST https://login.microsoftonline.com/16*73/oauth2/token HTTP/1.1 Content-Type: application/x-www-form-urlencoded client-request-id: 8aefb25e-195c-4331-969e-edc4be1b0079 return-client-request-id: true x-client-SKU: .NET x-client-Ver: 2.25.0.0 x-client-CPU: x64 x-client-OS: Microsoft Windows NT 6.2.9200.0 Host: login.microsoftonline.com Content-Length: 190 Expect: 100-continue Connection: Keep-Alive resource=http%3A%2F%2Fdaenet%2Fadapter.de&client_id=a9***fa8&client_secret=1y**Rk%3D&grant_type=client_credentials |
Interesting part in the request is body part, which contains grant type and credentials.
Following code snippet shows how to correctly create the request body in C#:
var body = $"resource={resourceUrl}&client_id={m_ClientId}&grant_type=client_credentials&client_secret={m_Secret}"; var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded"); |
How to acquire Token with Username and Password?
In a case of username and password authentication of a user request for obtaining of the token looks slightly different.
POST https://login.microsoftonline.com/16*73/oauth2/token HTTP/1.1 Content-Type: application/x-www-form-urlencoded client-request-id: 8aefb25e-195c-4331-969e-edc4be1b0079 return-client-request-id: true x-client-SKU: .NET x-client-Ver: 2.25.0.0 x-client-CPU: x64 x-client-OS: Microsoft Windows NT 6.2.9200.0 Host: login.microsoftonline.com Content-Length: 190 Expect: 100-continue Connection: Keep-Alive resource=http%3A%2F%2Fdaenet2Fadapter.de&client_id=a9***fa&grant_type=pasword&userName=damir&password=hopla |
As you see, this time grant_type is set to “password”, and request contains username and password.
Following code snippet shows how to correctly create the request body in C#:
var body = $"resource={resourceUrl}&client_id={clientId}&grant_type=password&username={userName}&password={password}"; var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded"); |
Posted
Nov 03 2016, 12:03 AM
by
Damir Dobric