Then you need to apply correct API permissions and grant the admin consent for your domain.
In the API permissions / Add a permission wizard, select Microsoft Graph and then Delegated permissions to find the following permission scopes listed:
string clientId = "Application (client) ID";
string tenantId = "Directory (tenant) ID";
// for @outlook.com/@hotmail accounts instead of setting .WithTenantId use:
// .WithAuthority(AadAuthorityAudience.PersonalMicrosoftAccount)
var app = PublicClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.WithDefaultRedirectUri()
.Build();
// This allows saving access/refresh tokens to some storage
TokenCacheHelper.EnableSerialization(app.UserTokenCache);
var scopes = new string[]
{
"offline_access",
"email",
"https://outlook.office.com/IMAP.AccessAsUser.All",
"https://outlook.office.com/POP.AccessAsUser.All",
"https://outlook.office.com/SMTP.Send",
};
In addition, you should request offline_access scope. When a user approves the offline_access scope, your app can receive refresh tokens from the Microsoft identity platform token endpoint. Refresh tokens are long-lived. Your app can get new access tokens as older ones expire.
Now acquire the access token and user email address:
var app = PublicClientApplicationBuilder
.Create(clientId)
.WithAuthority(
AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount
)
.WithDefaultRedirectUri()
.Build();
Token serialization
Below is a simple implementation that saves MSAL token cache to file:
static class TokenCacheHelper
{
public static void EnableSerialization(ITokenCache tokenCache)
{
tokenCache.SetBeforeAccess(BeforeAccessNotification);
tokenCache.SetAfterAccess(AfterAccessNotification);
}
private static readonly string _fileName = "msalcache.bin3";
private static readonly object _fileLock = new object();
private static void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
lock (_fileLock)
{
byte[] data = null;
if (File.Exists(_fileName))
data = File.ReadAllBytes(_fileName);
args.TokenCache.DeserializeMsalV3(data);
}
}
private static void AfterAccessNotification(TokenCacheNotificationArgs args)
{
if (args.HasStateChanged)
{
lock (_fileLock)
{
byte[] data = args.TokenCache.SerializeMsalV3();
File.WriteAllBytes(_fileName, data);
}
}
}
};
Please note that most likely you should store this cache in an encrypted form in some kind of a database. Consider using MSAL token serialization implementations available here:
Here’s the latest version that supports Visual Studio 2019.
Extension is convention based. It matches ClassName file with ClassNameTest or ClassNameTests and vice-versa, so you can easily navigate to the test file and back.
Here are some screenshots:
Here’s the toolbar name, in case it is not added automatically: