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.
https://developer.microsoft.com/en-us/graph/blogs/announcing-30-days-of-microsoft-graph-blog-series/#
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 ;
}
}
}