1.)
i am trying to rollout a CalendarSync to several different organizations, in an effort to reduce work by the org. admins. So to say I am looking for ways to automate the microsoft entra stuff:
2.)
I have seen there are several calls from Graph API c#, example to create an application. --> Which is what I need but the problem is authorization ... in every authorization i have tried by now there is only a login via tenantId+ClientId (and some use ClientSecret too)
--> But as the organization does not have any apps created how can I login via code?
Here is what I tried but i keep getting stuck because every auth method needs an app id (cleintid) and the organizations do not have any apps in entra (they are first time starting to use it)
public async Task CreateApp(string tenantId)
{
try
{
var confidentialClientApplication = ConfidentialClientApplicationBuilder.Create("clientId")
.WithClientSecret("clientSecret")
.WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}"))
.Build();
var authProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient graphClientApp = new GraphServiceClient(authProvider);
var newApp = new Application
{
DisplayName = "My New Application",
SignInAudience = "AzureADMyOrg", // Single tenant app
Api = new ApiApplication
{
RequestedAccessTokenVersion = 2
}
};
var result = await graphClientApp.Applications.PostAsync(newApp);
}
catch (Exception ex) { }
} ```
3.) Here is my working Authorization, which I use for CalendarSync (works flawlessly), but the problem is in the App creation i still need the clientId to logonto via graph ...
TokenCachePersistenceOptions TokenCachePersistenceOptions = new TokenCachePersistenceOptions { UnsafeAllowUnencryptedStorage = false };
InteractiveBrowserCredential credential = null;
credential = new InteractiveBrowserCredential(new InteractiveBrowserCredentialOptions
{
TenantId = tenantId,
ClientId = clientId,
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
RedirectUri = new Uri("http://localhost"),
TokenCachePersistenceOptions = TokenCachePersistenceOptions
});
GraphClient = new GraphServiceClient(credential);
After a few days of research i found myself out of the problem here it is for anyone who may need it:
!!! USE AZURE WEB CLI CLIENT ID FOR STEP 1 & 3!!!
1.) in code call this link of microsoft https://login.microsoftonline.com/common/oauth2/v2.0/devicecode and request a device code
2.) give the device code to user and the URL for login which is in json.RootElement.GetProperty("verification_uri")
3.) poll the https://login.microsoftonline.com/common/oauth2/v2.0/token to get the access token until it gives u a successfull token (until the user logins succesfully), each 5secs for example
4.) congrats you now have the access token and can register an app
here is some code for the different steps 1.)
using (var client = new HttpClient())
{
var content = new StringContent("client_id=AZURE WEB CLI CLIENT ID&scope=https://graph.microsoft.com/.default", Encoding.UTF8, "application/x-www-form-urlencoded");
var response = await client.PostAsync("https://login.microsoftonline.com/common/oauth2/v2.0/devicecode", content);
var responseBody = await response.Content.ReadAsStringAsync();
var json = JsonDocument.Parse(responseBody);
string verificationUri = json.RootElement.GetProperty("verification_uri").GetString();
string userCode = json.RootElement.GetProperty("user_code").GetString();
string deviceCode = json.RootElement.GetProperty("device_code").GetString();
string fullVerificationUrl = $"{verificationUri}?otc={Uri.EscapeDataString(userCode)}";
System.Diagnostics.Process.Start(new ProcessStartInfo
{
FileName = fullVerificationUrl,
UseShellExecute = true // Ensures the default browser is used
});
Console.WriteLine("Go to: " + verificationUri);
Console.WriteLine("Enter code: " + userCode);
Console.WriteLine("Enter code: " + deviceCode);
return (deviceCode, userCode); // Returning both deviceCode and userCode
}
3.)
var content = new StringContent($"client_id=0azure web cli id again client&grant_type=device_code&device_code={deviceCode}", Encoding.UTF8, "application/x-www-form-urlencoded");
var response = await client.PostAsync("https://login.microsoftonline.com/common/oauth2/v2.0/token", content);
var responseBody = await response.Content.ReadAsStringAsync();
var json = JsonDocument.Parse(responseBody);
var token = json.RootElement.GetProperty("access_token").GetString();
if(token != null)
{
return token;
}
4.)
var authProvider = new BaseBearerTokenAuthenticationProvider(new AccessTokenProvider(token));
var graphAccessToken = new GraphServiceClient(authProvider);
var apps = await graphAccessToken.Applications.GetAsync(); //for all aplications
public class AccessTokenProvider : IAccessTokenProvider
{
private readonly string _token;
public AccessTokenProvider(string token)
{
_token = token;
}
public Task<string> GetAuthorizationTokenAsync(Uri uri, Dictionary<string, object> additionalAuthParameters, System.Threading.CancellationToken cancellationToken)
{
// Simply return the token we already have
return Task.FromResult(_token);
}
public AllowedHostsValidator AllowedHostsValidator => new AllowedHostsValidator();
}