Introduction
In this article, we will learn how to generate Jwt security token for Application pool identity or logged on user using OAuth 2 from ADFS.
Background
If you are interested, please go through Application pool identities. Now a days, keeping user credentials in any config files or any other resource files is a little dangerous. Instead, we can use application pool identity feature.
It's safer than keeping credentials in any form of source.
Refer to this link.
Using the Code
I built and pushed nuget package in the nuget server called “OAuth2 Authorization Provider 1.0.0”, it has all the pre work done.
Nuget package manager command to install package: Install-Package OAuth2.Authorization
All you need to do is place the appropriate ADFS OAuth 2 configurations in the web or app config files and invoke helper functions from the nuget package mentioned above.
For more information about OAuth 2 specifications, please go through this link.
In this article, we use two ways to get JWT token. They are:
- Adal flow
- OAuth code flow
Way 1: Using Adal Flow
Config Dependency
<add key="AdfsInstance" value=""/>
<add key="ClientId" value=""/>
<add key="Resource" value=""/>
<add key="RedirectUri" value="http://localhost:56194/redirect"/>
<add key="AdfsAuthorityUrl" value="https://{0}/adfs/ls/{1}" />
Provide the above configuration values in the appSettings
section and invoke the below function call which is available in the “OAuth2 Authorization Provider 1.0.0” nuget package.
AdfsAuthorization.GetAdfsOAuthJwtAccessTokenForWinAppUserUsingAdal()
How It Works
Internally, it uses Microsoft.IdentityModel.Clients.ActiveDirectory
nuget package to create authenticate context for ADFS. Authentication context requires resource
, clientId
, redirectUri
, adfsInstance
and AuthorityUrl
parameters to provide the Jwt token for the logged on user.
Complete Code
if (!AdfsConfiguration.IsInitialized) throw new SecurityException
(Constants.AdfsConfigurationInitilizationExceptionMessage);
if (string.IsNullOrEmpty(AdfsConfiguration.AdfsAuthorityUrl))
throw new SecurityException
(Constants.AdfsConfigurationAdfsAuthorityUrlInitilizationExceptionMessage);
try
{
var authenticationContext = new AuthenticationContext
(string.Format(AdfsConfiguration.AdfsAuthorityUrl, AdfsConfiguration.AdfsInstance,
AdfsConfiguration.Resource), false);
var asyncRequest = authenticationContext.AcquireTokenAsync
(AdfsConfiguration.Resource, AdfsConfiguration.ClientId,
new Uri(AdfsConfiguration.RedirectUri), new PlatformParameters(PromptBehavior.Auto));
var accessToken = asyncRequest.Result.AccessToken;
return accessToken;
}
catch (Exception exp)
{
var additionalInfo = $" additionalInfo : [authenticationContext :
{string.Format(AdfsConfiguration.AdfsAuthorityUrl, AdfsConfiguration.AdfsInstance,
AdfsConfiguration.Resource)}]";
throw new SecurityException
($"AdfsAuthorization.GetAdfsOAuthJwtAccessTokenForWinAppUserUsingAdal is failed,
{additionalInfo}", exp);
}
Way 2: Using OAuth2 Authorization Code Flow
It has two processes:
- First, we need to get OAuth code from adfs server based on
clientId
, resource
and redirecturi
(which is already configured for the application in the ADFS server). - After successfully getting Auth code from ADFS, we have to hand over the Auth code again to the ADFS server to provide Jwt token for the concerned ADFS user.
Config Dependency
<add key="AdfsInstance" value=""/>
<add key="ClientId" value=""/>
<add key="Resource" value=""/>
<add key="RedirectUri" value="http://localhost:56194/redirect"/>
<add key="AdfsTokenServiceUrl" value="https://{0}/adfs/oauth2/token/"/>
Provide the above configuration in the appSetting
section and invoke the below lines of code, you are all done (which is already available in the nuget package).
await AuthorizationManager.GetAdfsOAuthJwtAccessTokenForWinAppUserUsingAuthCodeAsync()
How It Works
To get auth code, you need to make HttpClient
request by providing proper ADFS authentication url.
Complete Code
var authUrl = string.Format(AdfsConfiguration.AdfsAuthUrl, AdfsConfiguration.AdfsInstance,
AdfsConfiguration.ClientId, AdfsConfiguration.Resource,
AdfsConfiguration.UrlEncodedRedirectUri);
var authCode = "";
try
{
do
{
var result = await Client.GetAsync(authUrl);
await result.Content.ReadAsStringAsync();
IEnumerable<string> values;
if (result.Headers.TryGetValues("location", out values))
{
foreach (string s in values)
{
if (s.Contains("code="))
{
authUrl = "";
authCode = s.Substring(s.IndexOf("code=", StringComparison.Ordinal) + 5);
}
else
{
authUrl = s;
}
}
}
else
{
authUrl = "";
}
} while (!string.IsNullOrEmpty(authUrl));
return authCode;
}
catch (Exception exp)
{
var additionalInfo = $"additionalInfo : [authUrl: {authUrl}]";
throw new SecurityException
($"AdfsAuthorization.GetAuthCodeForWinAppUserAsync is failed, {additionalInfo}", exp);
}
After getting Authcode
, use WebClient
to get Jwt token, which is in encrypted format. If you want to see what it contains, then you need to have the appropriate certificate to validate and see what it has. This ability is also available in the nuget.
Complete Code
var client = new WebClient();
try
{
if (AdfsConfiguration.UseProxy == "Y")
{
var proxyObject = new WebProxy("Proxy", 80)
{ Credentials = CredentialCache.DefaultNetworkCredentials };
client.Proxy = proxyObject;
}
Uri address = new Uri
(string.Format(AdfsConfiguration.AdfsTokenServiceUrl, AdfsConfiguration.AdfsInstance));
Uri redirectAddress = new Uri(AdfsConfiguration.RedirectUri);
NameValueCollection values = new NameValueCollection
{
{"client_id", AdfsConfiguration.ClientId},
{"grant_type", "authorization_code"},
{"code", code},
{"redirect_uri", redirectAddress.ToString()}
};
byte[] responseBytes = client.UploadValues(address, "POST", values);
string response = System.Text.Encoding.UTF8.GetString(responseBytes);
return response;
}
catch (Exception exp)
{
var additionalInfo = $" additionalInfo :
[address: {string.Format(AdfsConfiguration.AdfsTokenServiceUrl,
AdfsConfiguration.AdfsInstance) }, redirect Uri :{AdfsConfiguration.RedirectUri}]";
throw new SecurityException($"AdfsAuthorization.GetAdfsOAuthTokenByAuthCode is failed,
{additionalInfo}", exp);
}
finally
{
client.Dispose();
}
That’s all to get Jwt token for the logged on or application pool identity from the ADFS server.
Along with this article, I have attached the sample testing tool to play around (Winform - test application).
History