how to use graph api / sdk with AD B2C - asp.net-mvc

I am trying to simply create a user using Graph API sdk against my AD B2C tenant but I keep running into issues. I am following the documentation here: https://learn.microsoft.com/en-us/graph/api/user-post-users?view=graph-rest-1.0&tabs=csharp
The first error I received was that “the domain portion of the userPrincipalName property is invalid. You must use one of the verified domain names in your organization”. After looking around, I found this document that states that the CreationType property must be set to "LocalAccount". When I tried that, I got the error that “one or more properties contains invalid values.”
The error doesn't give any details as to which property is invalid! Can someone at Microsoft please point me to an appropriate document of how to get this working? It seems that there might be some confusion in the documentation where the API is possibly targeting AD as opposed to AD B2C. But I do not have an AD tenant, just an AD B2C tenant, and that's what I am targeting. Again, I am using the latest version of the SDK.

I was able to figure out the issue. For AD B2C, I am supposed to attach an ObjectIdentity to the User object I am passing to be created.
Below is the code:
var identity = new ObjectIdentity
{
Issuer = Globals.Tenant,
IssuerAssignedId = email,
SignInType = "emailAddress"
};
var graphClient = GetGraphServiceClient();
var user = new User
{
DisplayName = fullName,
PasswordProfile = new PasswordProfile
{
Password = password,
ForceChangePasswordNextSignIn = forceChangePasswordSignIn
},
PasswordPolicies = "DisablePasswordExpiration",
AccountEnabled = enabled,
CreationType = "LocalAccount",
Identities = new ObjectIdentity[] { identity }
};
var userInfo = await graphClient.Users.Request().AddAsync(user);
return userInfo;

Related

Error in SharePoint oAuth Authentication using Sharepoint Online CSOM and PnP in .net core

I am trying to make sharepoint authentication using oAuth(Azure AD App) using Sharepoint Online CSOM and PnP, but it gives error "The given key was not present in the dictionary.". I have created Azure AD App and added API permission for Sharepoint AllSite.FullControl in that app.
I am using trial sharepoint tenant.
Here is my code snippets:
ClientContext _sharepointContaxt = null;
string Username = [Username];
string Password = [Password];
string AppId="67b1845e-88b1-4e6c-b7db-7f1d3abe3b06";
Uri site = new Uri([Sharepoint_site_url]);
using (var authenticationManager = new AuthenticationManager("67b1845e-88b1-4e6c-b7db-7f1e3aae3a06"))
using (_sharepointContaxt = authenticationManager.GetContext(site, Username, SecurePassword(Password)))
{
Web web = _sharepointContaxt.Web;
_sharepointContaxt.Load(web);
_sharepointContaxt.ExecuteQuery();
}
I faced the same "The given key was not present in the dictionary." issue whenever I occasionally sent Post request to Azure AD in a for loop. I'm not sure if this failure scenario is as the same as yours.
One of my debug way is to check the dictionary and see which "given key" was lost. In AuthenticationManager class, there is a private method called AcquireTokenAsync. This method is to request Azure AD to return SPO accessing token, and save it as a Json format in variable tokenResult, and then use GetProperty("access_token") to get token.
If Azure AD did not return SPO token for some reason, access_token might not be available in the tokenResult, result in the error code you saw.
In this case, error message in tokenResult help you to see the reason why Azure AD did not return the token.

Microsoft Graph API 403 error Failed to get license

As part of an automated process to create teams and channels need to provision the email.
Provisioning the email is a delegated operation whereas the initial teams and channel creation is 'application' thus requires no user involvement.
Have created an 'automation' AD user with minimal system access and created the associtated Azure 'application' with the appropriate Graph permissions - and this works no problem however for the 'automation' user getting:
Failed to get license information for the user. Ensure user has a valid Office365 license assigned to them
The message is self explanatory - so the question is, is it possible to perform basic Teams graphAPI operations such as provisioning email addresses and maybe sending messages without an O365 license - something like a Guest account?
The following code works for accounts with o365 licenses:
var UserName = "automationbotuser#somewhere.com";
var Password= "2w234234##$$%^^&^&*(erfwerwepassword";
var TenantId= "azuretentant";
var Client_Id= "azureappclientid";
var teamId = "b2342300d12-923e-46sdfsd5e-ae98-9132424db2250bc";
var projectChannel = "19:e5fe8e53ee6brwerwf8b3323438ab59913ef42#thread.tacv2";
// using Azure.Identity;
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
//create credentials
var userNamePasswordCredential = new UsernamePasswordCredential(
UserName, Password, TenantId, Client_Id, options);
var graphClient = new GraphServiceClient(userNamePasswordCredential);
//do a basic call to verify we can see something..
var user = await graphClient.Me.Request().GetAsync();
//provision the email address
await graphClient.Teams[$"{teamId}"].Channels[$"{projectChannel}"].ProvisionEmail()
.Request().PostAsync();
//remove it
await graphClient.Teams[$"{teamId}"].Channels[$"{projectChannel}"].RemoveEmail()
.Request().PostAsync();

Docusign iOS SDK directly sending envelope without opening anything also not asking to do the signature

I have created a template in docusign web and using its template id, i am calling the function from iOS SDK.
TemplatesManager.sharedInstance.displayTemplateForSignature(templateId: templateId, controller: self, tabData: tabData, recipientData: recipientData, customFields:customFields, onlineSign: onlineSign, attachmentUrl: attachmentUrl) { (controller, errMsg) in
print(errMsg)
}
The recipient data i am sending is
let recipientDatum = DSMRecipientDefault()
// Use recipient roleName (other option to use recipient-id) to find unique recipient in the template
recipientDatum.recipientRoleName = "Client"
recipientDatum.recipientSelectorType = .recipientRoleName
recipientDatum.recipientType = .inPersonSigner
// In-person-signer name
recipientDatum.inPersonSignerName = "Akshay Somkuwar"
// Host name (must match the name on the account) and email
recipientDatum.recipientName = "Akshay Somkuwar"
recipientDatum.recipientEmail = "akshay.s.somkuwar#gmail.com"
let recipientData: Array = [recipientDatum]
Same recipient is added for template in docusign website
Also i have added observers for DSMSigningCompleted and DSMSigningCancelled to get envelopeId.
Now when i am calling this function displayTemplateForSignature no screen is opening to show the PDF or To sign the PDF, without asking for signature, the envelope is directly sent to the recipient. and i am getting this response in console with notification.
name = DSMSigningCompletedNotification, object = Optional(<Public_Adjuster.AgreementSignViewController: 0x110bb8060>), userInfo = Optional([AnyHashable("templateId"): 506346f5-7adb-4132-b15f-d288aa268398, AnyHashable("signingMode"): online, AnyHashable("envelopeId"): 2eeeeda8-5b74-4930-904e-94b2ce6451ac])
I want to open the pdf for the passed templateId but its not opening the pdf nor its asking for signature, and its directly sent to the recipient.
Any help will be appreciated, Thank you.
This behaviour, sending the envelope directly, is triggered when DocuSign SDK can not find any signers in the template/envelope that matches the logged-in user. Given that you are using the recipientDefaults, ensure that your signer information on the template (preset signer on the DocuSign web) matches the Account information exactly with the recipientDefaults object.
You may compare it with .
One issue I noticed is the signer type is set to need to sign which corresponds to a remoteSigner on the DocuSign web. And on the recipientDefaults object it's set as inPersonSigner. It should be .signer corresponding to DSMRecipientTypeSigner.
recipientDatum.recipientType = .signer.
Or you may change the need to sign to in person signer on the DocuSign web.
Another suggestion is to remove the name & email from the template screenshot shared and keep that empty as the client app is passing name & email with the recipientDefaults object to the SDK.
More details: How to set recipient defaults

Automatic Update to Microsoft Graph API Subscription

I have created webhook project with Microsoft Graph API to monitor Office 365 inbox.
I made a UpdateSubscription action method which renews it for 3 days only as according to the documentation provide on https://graph.microsoft.io/en-us/docs/api-reference/v1.0/resources/subscription
Below is the code snippet of how I'am facilitating the HTTP request to update the subscription
AuthenticationResult authResult = await AuthHelper.GetAccessTokenAsync();
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Build the request.
string subscriptionsEndpoint = "https://graph.microsoft.com/v1.0/subscriptions/"+id;
var method = new HttpMethod("PATCH");
HttpRequestMessage request = new HttpRequestMessage(method, subscriptionsEndpoint);
//get the current time
var subscription = new Subscription
{
//Id = id,
ExpirationDateTime = DateTime.UtcNow + new TimeSpan(0, 0, 4230, 0)
};
Is there a way to auto update without the user pressing the button to 'update'?
since the authorization-headers requires AuthResult.accessToken which will require the user to sign in to Office365 account.
Please advice
An option available to you is the service or daemon approach (https://graph.microsoft.io/en-us/docs/authorization/app_only). Instead of authenticating with a logged-in user you're able to renew the subscription at the application level using a Bearer token which is in turn generated by the CLIENT_SECRET from Azure AD.
I don't think storing tokens in the database is the right approach here. My understanding is that security tokens are never appropriate for a database.
In fact, I don't quite understand the need to have the user log in at all here, unless there are parts to the program that you didn't mention. A service like the one I mentioned can monitor a mailbox without a user being there, or else if the program requires the user to be there, there really isn't an issue of lost credentials.
You can use this approach to fetch accesstoken from azure using grant_type a password. PLease find the below screenshot.

Error:”invalid_grant”, Description:””, Uri:”” while using service account from my local machine

I got below error while using service account from my local machine
Error:
invalid_grant”, Description:””, Uri:””.
see code below -
string[] scopes = new string[] {
AnalyticsService.Scope.Analytics
}; // view and manage your Google Analytics data
var keyFilePath = #
"c:\xxxxxxx.p12"; // Downloaded from https://console.developers.google.com
var serviceAccountEmail = "xxxxx#developer.gserviceaccount.com"; // found https://console.developers.google.com
//loading the Key file
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) {
Scopes = scopes
}.FromCertificate(certificate));
var service = new AnalyticsService(new BaseClientService.Initializer() {
HttpClientInitializer = credential,
ApplicationName = "Analytics API Sample",
});
string profileId = "xxxxxx";
DataResource.RealtimeResource.GetRequest request = service.Data.Realtime.Get(String.Format("ga:{0}", profileId), "rt:activeUsers");
RealtimeData feed = request.Execute();
invalid_grant has two common causes.
Your server’s clock is not in sync with NTP. (Solution: check the server time if its incorrect fix it. )
The refresh token limit has been exceeded. (Solution: Nothing you can do they cant have more refresh tokens in use)
Applications can request multiple refresh tokens. For example, this is useful in situations where a user wants to install an application on multiple machines. In this case, two refresh tokens are required, one for each installation. When the number of refresh tokens exceeds the limit, older tokens become invalid. If the application attempts to use an invalidated refresh token, an invalid_grant error response is returned. The limit for each unique pair of OAuth 2.0 client and is 25 refresh tokens (note that this limit is subject to change). If the application continues to request refresh tokens for the same Client/Account pair, once the 26th token is issued, the 1st refresh token that was previously issued will become invalid. The 27th requested refresh token would invalidate the 2nd previously issued token and so on.
I have also read of a third which is if you don't include access_type=offline in your request. I have never had an issue with this one myself

Resources