Automatic Update to Microsoft Graph API Subscription - asp.net-mvc

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.

Related

Re enter without password after revoke salesforce oauth token

I built a simple app that allows our customers to gather specific information from their Salesforce system. For authentication I used "WebServer Flow", which allows a user to log in to our site with his Salesforce account.
I should of course allow the user to log out of his account. But for some reason, even though I send a Revoke request to Salesforce and get an OK response, when the user redirected again to the Salesforce login page, it automatically logs in to the previous account without re-entering details.
this is the logout action in my backend,
public async Task<ContentResult> LogOutFromSalseforce(string code)
{
AuthenticationClient auth;
bool hasAuth = AuthSessionWrapper.AuthDic.TryGetValue(code, out auth);
if (!hasAuth) return Content(JsonConvert.SerializeObject(new { error = "session expired" }), "application/json");
var url = auth.InstanceUrl + _revokeEndpointUrl;
var cl = new HttpClient();
var res = await cl.PostAsync(url, new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("token", auth.RefreshToken) }));
AuthSessionWrapper.AuthDic.Remove(code);
return Content(JsonConvert.SerializeObject(new { success = res.StatusCode == HttpStatusCode.OK }), "application/json");
}
And after call from client to this action he redirected to our login page.
I found that even if i call to this revoke endpoint from client it's not work.
only if the user enter in another tab to Salesforce and click logout there, he need to re enter his details to login again to our site.
What I'm doing wrong?
If someone get into the same problem, I solved it with add "&prompt=login" to the login redirect url.

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();

Twilio configuration Profile SID

I am using the Twilio Video API. In my node.js I used this code,
var grant = new VideoGrant();
It requires configurationProfileSid but I can't find docs on how to get it?
I think it is a capability token.
But how can I get it using twilio node js?
Or is there any other way to get it?
Twilio developer evangelist here.
Configuration Profiles used to be required, but have been deprecated. So you no longer need the configurationProfileSid. You can give access to particular rooms though.
Here's an example Node.js application that generates access tokens for a Video application. The important part is the route that generates the token:
app.get('/', function(request, response) {
// Create an access token which we will sign and return to the client,
// containing the grant we just created
var token = new AccessToken(
process.env.TWILIO_ACCOUNT_SID,
process.env.TWILIO_API_KEY,
process.env.TWILIO_API_SECRET
);
// Assign identity to the token
token.identity = request.query.identity || 'identity';
// Grant the access token Twilio Video capabilities
var grant = new VideoGrant();
grant.room = request.query.room;
token.addGrant(grant);
// Serialize the token to a JWT string
response.send(token.toJwt());
});
This documentation on access tokens should help too.

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

Token Response Exception after 2-3 min in retriving Google Contacts of user

I am getting Token Response Exception after 1-2 min continuously. After 2-3 min contacts coming and then after 2-3 min again token exception is coming.
Below is the Exception
com.google.api.client.auth.oauth2.TokenResponseException: 403 OK
<p class="large"><b>403.</b>
<ins>That's an error.</ins></p><p class="large">You are not authorised to perform this request. <ins>That's all we know.</ins>
</p>
I am retriving contacts of user , Below is my code,
ContactsService contactService = new ContactsService("appName");
contactService.setOAuth2Credentials(getCredentials());
Below is getCredentials() method.
public GoogleCredential getCredentials() {
GoogleCredential credential = null;
try{
Collection<String> SCOPES = new ArrayList<String>();
SCOPES.add("https://www.googleapis.com/auth/userinfo.profile");
SCOPES.add("https://www.google.com/m8/feeds");
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(SCOPES)
.setServiceAccountUser(adminEmailAddress)
.setServiceAccountPrivateKeyFromP12File(new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
.build().setExpiresInSeconds(min);
credential.refreshToken();
} catch(Exception e){
e.printStackTrace();
}
return credential;
}
can anyone tell me how to keep token valid for max time or how to deal with above problem.?
You need to understand how Oauth2 works I think you should read
Using OAuth 2.0 to Access Google APIs
Refresh the access token, if necessary.
Access tokens have limited lifetimes. If your application needs access
to a Google API beyond the lifetime of a single access token, it can
obtain a refresh token. A refresh token allows your application to
obtain new access tokens.
Note: Save refresh tokens in secure long-term storage and continue to
use them as long as they remain valid. Limits apply to the number of
refresh tokens that are issued per client-user combination, and per
user across all clients, and these limits are different. If your
application requests enough refresh tokens to go over one of the
limits, older refresh tokens stop working.
As stated in the doucmentation access tokens work for a limited amount of time. That being 1 hour you can't extend that. But you have the refreshToken you need in order to get a new AccessToken. RefreshTokens dont expire unless the user revokes your access. But in your case this wont happen becouse you are using a service account. So you can just rerun your code and get a new AccessToken
You have two options:
Check the time that is returned if your access token is about to expire then rerun the code and get a new one.
Wait until you get the error message then request a new access token.
The first option is best becouse google logs the number of errors you get from the API no reason to run something thats going to error on you. I normally request a new AccessToken 5 minutes before my old one is due to expire.

Resources