Every time I try to add a license to a user using the Microsoft Graph Api in C#, I get this error:
Microsoft.Graph.ServiceException: 'Code: Request_BadRequest
Message: License assignment cannot be done for user with invalid usage location.
My code is here
using Azure.Identity;
using Microsoft.Graph;
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "tenantid";
var clientId = "clientid";
var clientSecret = "clientsecret";
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var user = new User
{
AccountEnabled = true,
DisplayName = "test",
MailNickname = "test",
UserPrincipalName = "test#example.com",
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "random.1234"
}
};
var addLicenses = new List<AssignedLicense>()
{
new AssignedLicense
{
SkuId = Guid.Parse("314c4481-f395-4525-be8b-2ec4bb1e9d91")
}
};
var removeLicenses = Array.Empty<Guid>();
await graphClient.Users
.Request()
.AddAsync(user);
Console.WriteLine("Kullanıcı Açıldı");
await graphClient.Users["test#example.com"]
.AssignLicense(addLicenses, removeLicenses)
.Request()
.PostAsync();
Console.WriteLine("Lisans Eklendi");
When you create a new user you need to set UsageLocation.
Documentation says that usageLocation is required for users that will be assigned licenses due to legal requirement to check for availability of services in countries.
var user = new User
{
AccountEnabled = true,
DisplayName = "test",
MailNickname = "test",
UserPrincipalName = "test#example.com",
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "random.1234"
},
UsageLocation = "TR" // for Turkey
};
// rest of the code without changes
var addLicenses = new List<AssignedLicense>()
{
new AssignedLicense
{
SkuId = Guid.Parse("314c4481-f395-4525-be8b-2ec4bb1e9d91")
}
};
var removeLicenses = Array.Empty<Guid>();
await graphClient.Users
.Request()
.AddAsync(user);
Console.WriteLine("Kullanıcı Açıldı");
await graphClient.Users["test#example.com"]
.AssignLicense(addLicenses, removeLicenses)
.Request()
.PostAsync();
Console.WriteLine("Lisans Eklendi");
Related
[SOLVED, see the edits]
I am working in Linqpad 6, running a script that I made based on the following articles:
https://learn.microsoft.com/en-us/graph/api/user-post-users?view=graph-rest-1.0&tabs=csharp
https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS
Here is my script:
void Main()
{
Debug.WriteLine("yo");
UserCreator creator = new();
creator.CreateUser();
}
public class UserCreator
{
public async void CreateUser()
{
var scopes = new[] { "User.ReadWriteAll" };
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "<MY_TENANT_ID>";
// Value from app registration
var clientId = "<MY_APPLICATION_ID>";
var pca = PublicClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantId)
.Build();
// DelegateAuthenticationProvider is a simple auth provider implementation
// that allows you to define an async function to retrieve a token
// Alternatively, you can create a class that implements IAuthenticationProvider
// for more complex scenarios
var authProvider = new DelegateAuthenticationProvider(async (request) =>
{
// Use Microsoft.Identity.Client to retrieve token
var result = await pca.AcquireTokenByIntegratedWindowsAuth(scopes).ExecuteAsync();
request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
});
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var user = new User
{
AccountEnabled = true,
DisplayName = "John",
MailNickname = "John",
UserPrincipalName = "john#mail.com",
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "xWwvJ]6NMw+bWH-d"
}
};
await graphClient.Users
.Request()
.AddAsync(user);
}
}
I am trying to add a new user to an Azure AD B2C app, but the request is failing with an InnerException of:
"The system cannot contact a domain controller to service the authentication request."
I am suspecting I need more info for the script, such as the name of the registered App, but I cannot find anything about it in the documentation. I find it likely that the request is not returning the correct auth token.
Below is a screenshot of the error:
Updated code
This is my final, working result. Originally, I tried to create a user through my own account, but MFA got in the way. The actual way to do it, is through an app registration.
void Main()
{
UserCreator creator = new();
creator.CreateUser();
}
public class UserCreator
{
public async void CreateUser()
{
var clientId = "<CLIENT_ID>";
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "<TENANT_ID>";
var clientSecret = "<CLIENT_SECRET>";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
// https://learn.microsoft.com/dotnet/api/azure.identity.clientsecretcredential
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var user = new{
Email = "test#mail.dk",
DisplayName = "TestUser",
Username = "Someusername",
};
var invitation = new Invitation
{
InvitedUserEmailAddress = user.Email,
InvitedUser = new User
{
AccountEnabled = true,
DisplayName = "TestUser",
CreationType = "LocalAccount",
PasswordPolicies = "DisableStrongPassword",
PasswordProfile = new PasswordProfile
{
ForceChangePasswordNextSignIn = true,
Password = "Test123456",
}
},
InvitedUserType = "member",
SendInvitationMessage = true,
InviteRedirectUrl = "someurl.com"
};
await graphClient.Invitations
.Request()
.AddAsync(invitation);
Console.Write("completed");
}
}
Try to set Azure AD authority by .WithAuthority instead of WithTenantId.
There is a typo in your scopes. Required permission is User.ReadWrite.All not User.ReadWriteAll.
var scopes = new[] { "User.ReadWrite.All" };
...
var pca = PublicClientApplicationBuilder
.Create(clientId)
.WithAuthority($"https://login.microsoftonline.com/{tenantId}")
.WithDefaultRedirectUri()
.Build();
How to stop my livestream in YouTube while completed my live telecast using c#
How to stop the livestream Using c# Code, can you please give some suggestion
string[] scopes = { "https://www.googleapis.com/auth/youtube", "https://www.googleapis.com/auth/youtube.upload" };
var creadentails = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = YTPublishSettings.PublisherClientId,
ClientSecret = YTPublishSettings.PublisherClientSecret,
},
scopes, "user", default).Result;
if (creadentails.Token.IsExpired(SystemClock.Default))
creadentails.RefreshTokenAsync(CancellationToken.None).Wait();
var secrets = new ClientSecrets
{
ClientId = YTPublishSettings.PublisherClientId,
ClientSecret = YTPublishSettings.PublisherClientSecret,
};
var token = new TokenResponse { RefreshToken = creadentails.Token.RefreshToken };
var credentials = new UserCredential(new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer { ClientSecrets = secrets }),
"user", token);
var service = new YouTubeService(new BaseClientService.Initializer
{
HttpClientInitializer = credentials,
ApplicationName = "**************",
});
var broadcast = new LiveStream
{
Cdn = new CdnSettings
{
FrameRate = "35fps",
IngestionType = "rtmp",
Resolution = "720p"
},
Snippet = new LiveStreamSnippet
{
Description = Description,
Title = Title,
},
};
var request = service.LiveStreams.Delete(YTPublishSettings.PublisherId);
var response = request.Execute();
return new YouTubeStreamDeleteStatus()
{
success = "Deleted",
};
How can end My YouTube live stream API in c#?
I have create a c# custom application to create chat using one-on-one chat using user principal name. I want to show the response header into the Textbox when the user click the create button. I have follow the article below Get Response Header data from Post Call to get the response but currently I'm having some errors.
Coding part of Create Chat
private async void button2_Click(object sender, EventArgs e)
{
var scopes = new[] { "Directory.Read.All", "Directory.ReadWrite.All", "User.Read", "User.Read.All", "User.ReadBasic.All", "User.ReadWrite" };
{
// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "5exxxx3-376a-43b1-9xxx0c-ef3xxxf8bx0";
// Value from app registration
var clientId = "35xxx-5c92-4xxx9-8500-635xxxe8af";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var userName = "ng.xxxxxi.com";
var password = "Aaxxxxxx";
// https://learn.microsoft.com/dotnet/api/azure.identity.usernamepasswordcredential
var userNamePasswordCredential = new UsernamePasswordCredential(
userName, password, tenantId, clientId, options);
GraphServiceClient graphClient = new GraphServiceClient(userNamePasswordCredential, scopes);
var chat = new Chat
{
ChatType = ChatType.OneOnOne,
Members = new ChatMembersCollectionPage()
{
new AadUserConversationMember
{
Roles = new List<String>()
{
"owner"
},
AdditionalData = new Dictionary<string, object>()
{
{"user#odata.bind", "https://graph.microsoft.com/v1.0/users[comboBox2.Text]"}
}
},
new AadUserConversationMember
{
Roles = new List<String>()
{
"owner"
},
AdditionalData = new Dictionary<string, object>()
{
{"user#odata.bind", "https://graph.microsoft.com/v1.0/users/[comboBox3.Text]"}
}
}
}
};
var requestUrl = graphClient.Chats.Request().RequestUrl;
var content = "json_content";
var hrm = new HttpRequestMessage(HttpMethod.Post, requestUrl);
hrm.Content = new StringContent(content, System.Text.Encoding.UTF8, "aplication/json");
// Authenticate (add access token)
await graphClient.AuthenticationProvider.AuthenticateRequestAsync(hrm);
// Send the request and get the response.
var response = await graphClient.HttpProvider.SendAsync(hrm);
if (!response.IsSuccessStatusCode)
{
throw new ServiceException(
new Error
{
Code = response.StatusCode.ToString(),
Message = await response.Content.ReadAsStringAsync()
});
}
else
{
// read header values
var headerValues = response.Headers.GetValues(textBox2.Text);
}
await graphClient.Chats
.Request()
.AddAsync(chat);
}
}
I created a C# console application to send email using Microsoft Graph API. On adding Mail.Send Delegated Permission to my application, I see the following exception:
I have enabled 'Allow public client flows':
The application has Mail.Send permission:
Here is my code:
public async Task SendMail(string subject, string content, string recipientAddress)
{
var publicClientApplication = PublicClientApplicationBuilder
.Create("<client id>")
.WithTenantId("<tenant id>")
.Build();
string[] scopes = new string[] { "mail.send" };
UsernamePasswordProvider authProvider = new UsernamePasswordProvider(publicClientApplication, scopes);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var message = new Message
{
Subject = subject,
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = content
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress { Address = recipientAddress }
}
}
};
var securePassword = new SecureString();
foreach (char c in _senderPassword)
securePassword.AppendChar(c);
var saveToSentItems = true;
await graphClient.Me
.SendMail(message, saveToSentItems)
.Request().WithUsernamePassword(_senderAddress, securePassword)
.PostAsync();
}
What am I missing?
You need to meet the following points:
You must have Mail.Send delegation permissions, you can use jwt.ms to parse your access token to view scp claims:
2.Ensure that your account has an Exchange online license under O365 subscription. See: assign licenses to one user.
My code for your reference:
using Microsoft.Graph;
using Microsoft.Graph.Auth;
using Microsoft.Identity.Client;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace devicecode
{
class Program
{
static async Task Main(string[] args)
{
string graphScope = "User.Read User.ReadBasic.All Mail.Send Mail.Send.Shared";
var graphScopes = graphScope.Split(' ').ToArray();
// Build a client application.
IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
.Create("My clienid")
.Build();
DeviceCodeProvider authProvider = new DeviceCodeProvider(publicClientApplication, graphScopes);
// Create an authentication provider by passing in a client application and graph scopes.
// Create a new instance of GraphServiceClient with the authentication provider.
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var message = new Message
{
Subject = "Meet for lunch?",
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = "The new cafeteria is open."
},
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "mytestaccount"
}
}
}
};
var saveToSentItems = false;
await graphClient.Me
.SendMail(message, saveToSentItems)
.Request()
.PostAsync();
}
}
}
print:
I'm trying to do the following:
var confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(APP_ID)
.WithTenantId(AzureConfiguration.TenantId)
.WithClientSecret(APP_SECRET)
.Build();
var authProvider = new ClientCredentialProvider(confidentialClientApplication);
var client = new GraphServiceClient(GRAPH_URL, authProvider);
subscription = await client.Subscriptions.Request().AddAsync(new Subscription
{
ChangeType = "updated",
NotificationUrl = notificationUrl,
Resource = $"/groups/{CONTENT_GROUP_ID}/drive/root",
ExpirationDateTime = DateTimeOffset.UtcNow.AddMinutes(SubscriptionLength),
ClientState = Guid.NewGuid().ToString()
});
Content group is a valid group. The application has Files.ReadWrite.All and Group.ReadWrite.All at the application level, and the Grant Admin for button has been clicked.
This used to work with HTTPClient and REST with login like this:
var authContext = new AuthenticationContext($"https://login.microsoftonline.com/{AzureConfiguration.TenantId}");
var creds = new ClientCredential(APP_ID, APP_SECRET);
var authResult = await authContext.AcquireTokenAsync("https://graph.microsoft.com/", creds);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
and then calling it like this: with a helper function that just posts the json:
var result = await Post<Subscription, Subscription>(client, $"{GRAPH_URL}/subscriptions", new Subscription
{
ChangeType = "updated",
NotificationUrl = $"{apiUrl}/v1/SharepointNotifications/Notify",
Resource = $"/groups/{CONTENT_GROUP_ID}/drive/root",
ExpirationDateTime = DateTimeOffset.UtcNow.AddMinutes(SubscriptionLength),
ClientState = Guid.NewGuid().ToString()
});
(This code used to work but failed at this refresh of the subscription.)
I'm at a loss as to what's different and causing it not to work. How do I get this going?