Microsoft Graph
I am implementing a Graph solution for syncing office 365 groups in Azure AD. First of all you should be authenticated. We are using OAuth 2.0 for that.
Here is a very useful blog explaining the nuts and bolts.
I have made a little .NET Core console app for getting the Office 365 groups from Azure AD. I have put everything in one file for readability. I’ll hope this will get you started.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using Microsoft.Graph;
using Microsoft.Extensions.Configuration;
namespace ConsoleGraphTest
{
class Program
{
private static GraphServiceClient _graphServiceClient;
static void Main(string[] args)
{
// Load appsettings.json
var config = LoadAppSettings();
if (null == config)
{
Console.WriteLine("Missing or invalid appsettings.json file. Please see README.md for configuration instructions.");
return;
}
//Query using Graph SDK (preferred when possible)
GraphServiceClient graphClient = GetAuthenticatedGraphClient(config);
List<QueryOption> options = new List<QueryOption>
{
new QueryOption("$filter", "groupTypes/any(c:c+eq+'Unified')")
};
var graphResult = graphClient.Groups.Request(options).GetAsync().Result;
Console.WriteLine("--- Office 365 Groups ---\n");
foreach (var group in graphResult) {
Console.WriteLine(group.DisplayName);
}
Console.ReadKey();
}
private static GraphServiceClient GetAuthenticatedGraphClient(IConfigurationRoot config)
{
var authenticationProvider = CreateAuthorizationProvider(config);
_graphServiceClient = new GraphServiceClient(authenticationProvider);
return _graphServiceClient;
}
private static IAuthenticationProvider CreateAuthorizationProvider(IConfigurationRoot config)
{
var clientId = config["applicationId"];
var clientSecret = config["applicationSecret"];
var redirectUri = config["redirectUri"];
var certificate = config["certificate"];
var authority = $"https://login.microsoftonline.com/{config["tenantId"]}/v2.0";
//this specific scope means that application will default to what is defined in the application registration rather than using dynamic scopes
List<string> scopes = new List<string>();
scopes.Add("https://graph.microsoft.com/.default");
//Authenticate with certificate
var clientCred = new ClientCredential(new ClientAssertionCertificate(ReadCertificate(certificate)));
//You can also authenticate with a secret key
//var cca = new ConfidentialClientApplication(clientId, authority, redirectUri, new ClientCredential(clientSecret), null, null);
var cca = new ConfidentialClientApplication(clientId, authority, redirectUri, clientCred, null, null);
return new MsalAuthenticationProvider(cca, scopes.ToArray());
}
private static IConfigurationRoot LoadAppSettings()
{
try
{
var config = new ConfigurationBuilder()
.SetBasePath(System.IO.Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true)
.Build();
// Validate required settings
if (string.IsNullOrEmpty(config["applicationId"]) ||
string.IsNullOrEmpty(config["applicationSecret"]) ||
string.IsNullOrEmpty(config["redirectUri"]) ||
string.IsNullOrEmpty(config["tenantId"]) ||
string.IsNullOrEmpty(config["domain"]) ||
string.IsNullOrEmpty(config["certificate"]))
{
return null;
}
return config;
}
catch (System.IO.FileNotFoundException)
{
return null;
}
}
private static X509Certificate2 ReadCertificate(string certificateName)
{
if (string.IsNullOrWhiteSpace(certificateName))
{
throw new ArgumentException("certificateName should not be empty. Please set the CertificateName setting in the appsettings.json", nameof(certificateName));
}
X509Certificate2 cert = null;
using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = store.Certificates;
// Find unexpired certificates.
X509Certificate2Collection currentCerts = certCollection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
// From the collection of unexpired certificates, find the ones with the correct name.
X509Certificate2Collection signingCert = currentCerts.Find(X509FindType.FindBySubjectDistinguishedName, certificateName, false);
// Return the first certificate in the collection, has the right name and is current.
cert = signingCert.OfType<X509Certificate2>().OrderByDescending(c => c.NotBefore).FirstOrDefault();
}
return cert;
}
}
// This class encapsulates the details of getting a token from MSAL and exposes it via the
// IAuthenticationProvider interface so that GraphServiceClient or AuthHandler can use it.
// A significantly enhanced version of this class will in the future be available from
// the GraphSDK team. It will supports all the types of Client Application as defined by MSAL.
public class MsalAuthenticationProvider : IAuthenticationProvider
{
private ConfidentialClientApplication _clientApplication;
private string[] _scopes;
public MsalAuthenticationProvider(ConfidentialClientApplication clientApplication, string[] scopes)
{
_clientApplication = clientApplication;
_scopes = scopes;
}
/// <summary>
/// Update HttpRequestMessage with credentials
/// </summary>
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
var token = await GetTokenAsync();
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
}
/// <summary>
/// Acquire Token
/// </summary>
public async Task<string> GetTokenAsync()
{
AuthenticationResult authResult = null;
authResult = await _clientApplication.AcquireTokenForClientAsync(_scopes);
return authResult.AccessToken;
}
}
}