Last active
August 10, 2020 08:20
-
-
Save watahani/f09e17bae35730af5a3729952fe29d74 to your computer and use it in GitHub Desktop.
Azure AD Client Credential Flow sample using JWT Bearer Assertion
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Net.Http; | |
using System.Threading.Tasks; | |
using System.Collections.Generic; | |
using System.Security.Cryptography.X509Certificates; | |
using Microsoft.IdentityModel.JsonWebTokens; | |
using Microsoft.IdentityModel.Tokens; | |
namespace console | |
{ | |
class Program | |
{ | |
private static readonly HttpClient client = new HttpClient(); | |
private static readonly string clientId = "<client_id>"; | |
private static readonly string authority = "https://login.microsoftonline.com/<tenantid>"; | |
private static readonly string certThumbprint = "<thumbprint>"; | |
static async Task Main(string[] args) | |
{ | |
var clientAssertion = GenerateClientAssertion(); | |
var req = new HttpRequestMessage(); | |
var res = await client.PostAsync( $"{authority}/oauth2/v2.0/token", new FormUrlEncodedContent(new Dictionary<string, string>(){ | |
{"scope", "https://graph.microsoft.com/.default"}, | |
{"client_id", clientId}, | |
{"client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"}, | |
{"client_assertion", clientAssertion}, | |
{"grant_type", "client_credentials"} | |
})); | |
var body = await res.Content.ReadAsStringAsync(); | |
System.Console.WriteLine(body); | |
} | |
private static String GenerateClientAssertion() | |
{ | |
// https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/blob/edafefa8f6f96bdd8b654dd83fb34cd17e9ab1e2/tests/Microsoft.Identity.Test.Integration.net45/HeadlessTests/ConfidentialClientIntegrationTests.cs#L511 | |
var aud = $"{authority}/oauth2/token"; | |
var claims = new Dictionary<string, object>(){ | |
{ "aud", aud }, | |
{ "iss", clientId }, | |
{ "jti", Guid.NewGuid().ToString() }, | |
{ "sub", clientId } | |
}; | |
var signingCert = LoadCertificateByThumbprintFromCurrentCertMy(certThumbprint); | |
var signingCredentials = new X509SigningCredentials(signingCert); | |
var securityTokenDescriptor = new SecurityTokenDescriptor | |
{ | |
Claims = claims, | |
SigningCredentials = new X509SigningCredentials(signingCert) | |
}; | |
var handler = new JsonWebTokenHandler(); | |
var signedClientAssertion = handler.CreateToken(securityTokenDescriptor); | |
return signedClientAssertion; | |
} | |
private static X509Certificate2 LoadCertificateByThumbprintFromCurrentCertMy(String thumbprint) | |
{ | |
X509Store store = new X509Store(StoreLocation.CurrentUser); | |
try | |
{ | |
store.Open(OpenFlags.ReadOnly); | |
// Place all certificates in an X509Certificate2Collection object. | |
X509Certificate2Collection certCollection = store.Certificates; | |
// If using a certificate with a trusted root you do not need to FindByTimeValid, instead: | |
// currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certName, true); | |
X509Certificate2Collection currentCerts = certCollection.Find(X509FindType.FindByTimeValid, DateTime.Now, false); | |
X509Certificate2Collection signingCert = currentCerts.Find(X509FindType.FindByThumbprint, thumbprint, false); | |
if (signingCert.Count == 0) | |
return null; | |
// Return the first certificate in the collection, has the right name and is current. | |
return signingCert[0]; | |
} | |
finally | |
{ | |
store.Close(); | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment