In a service-to-service oauth communication, I'm trying to send a token request to an external Oauth Token Endpoint and to use the token as a Bearer for a Microsoft solution (Dynamics CRM v.9.1 On-Premises). The platform used should not be so relevant since we are talking about OAuth which is an RFC documented protocol The code I used so far to get the token and to make the request to the Resource Server with the Bearer is the one pasted below.
When I make the request to the Resource server i get the following error.
Bearer error=invalid_token, error_description=Error during token validation!,
authorization_uri=https://mytokenserver/login,
resource_id=https://myresourceserver/
The problem in the response is that it shows an "authorization_uri" which is https://mytokenserver/login , which is wrong. My authorization uri is : https://mytokenserver/oauth2/authorize
I wasn't able to find any setting in the microsoft crm platform so my best guess is that I'm generating a wrong Assertion JWT in the code below.
Any experience with that ? (just a small detail, the oauth token server is written in java)
static private string clientId = "rb7ddjkjWd8djkjlk";
static private string pfxFile = "C:\\keystore.p12";
static private string pass = "blabla";
static private string authorityUri = "https://mytokenserver/oauth2/token";
static private Uri environmentUri = new Uri("https://myresourceserver/api/data/v9.1");
static async Task<string> RequestTokenAndSendRequestToResourceServerAsync()
{
if (tokenCache != "")
return tokenCache;
var client = new HttpClient();
var clientToken = GetJwtToken(pfxFile, pass, clientId, authorityUri, 180);
Console.WriteLine("JWT Token is: " + clientToken);
Parameters parameters = new Parameters
{
new KeyValuePair<string, string>("audience", clientId),
new KeyValuePair<string, string>("requested_token_type", "urn:ietf:params:oauth:token-type:access_token")
};
ClientCredentialsTokenRequest clientCredentialsRequest = new ClientCredentialsTokenRequest
{
Parameters = parameters,
GrantType = OidcConstants.GrantTypes.ClientCredentials,
Address = authorityUri,
ClientAssertion =
{
Type = OidcConstants.ClientAssertionTypes.JwtBearer,
Value = clientToken
}
};
clientCredentialsRequest.ClientCredentialStyle = ClientCredentialStyle.PostBody;
var response = await client.RequestClientCredentialsTokenAsync(clientCredentialsRequest);
if (response.IsError)
{
Console.WriteLine(response.HttpStatusCode);
Console.WriteLine(response.ErrorDescription);
Console.WriteLine(response.ErrorType.ToString());
throw response.Exception;
}
Console.WriteLine("Access Token is: " + response.AccessToken);
// Set up the HTTP client
var httpclient = new HttpClient
{
BaseAddress = new Uri("https://myresourceserver"),
Timeout = new TimeSpan(0, 2, 0) // Standard two minute timeout.
};
HttpRequestHeaders headers = httpclient.DefaultRequestHeaders;
headers.Authorization = new AuthenticationHeaderValue("Bearer", response.AccessToken);
headers.Add("OData-MaxVersion", "4.0");
headers.Add("OData-Version", "4.0");
headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Web API call
var result = httpclient.GetAsync("WhoAmI").Result;
var jsonResponse = await result.Content.ReadAsStringAsync();
Console.WriteLine(result.ReasonPhrase);
Console.WriteLine(jsonResponse);
result.EnsureSuccessStatusCode();
return response.AccessToken;
}
public static string GetJwtToken(string pfxFilePath, string password, string issuer, string audience, int expiryInMinutes)
{
Console.WriteLine("Creating JWT Token");
string jwtToken = string.Empty;
JwtSecurityToken jwtSecurityToken;
X509Certificate2 signingCert = new X509Certificate2(pfxFilePath, password);
X509SecurityKey privateKey = new X509SecurityKey(signingCert);
var descriptor = new SecurityTokenDescriptor
{
// Audience = auth2/token endpoint, Issuer = clientId
Issuer = issuer,
Audience = audience,
IssuedAt = DateTime.UtcNow,
Expires = DateTime.UtcNow.AddMinutes(expiryInMinutes),
Subject = new ClaimsIdentity(new List<Claim>
{
new Claim(JwtClaimTypes.Subject, issuer),
new Claim(Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}),
SigningCredentials = new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256)
};
var handler = new JwtSecurityTokenHandler();
handler.SetDefaultTimesOnTokenCreation = false;
jwtSecurityToken = handler.CreateJwtSecurityToken(descriptor);
jwtSecurityToken.Header.Remove("kid");
jwtToken = handler.WriteToken(jwtSecurityToken);
return jwtToken;
}