I m developing an App which has to write on google spreadsheet.
My application used to work fine until Google changed is Auth API two months ago.
Following the link with the new process.
Google.GData.Client.GDataRequestException - Authentication suddenly fails in old code
I have a google account me#company.com which is managed by my boss account company#gmail.com.
I want to write in a spreadsheet named "Bank Details" shared to me from my boss account.(the onwer is "mycompany")
I generated a key.p12 from my account and it works fine, I can write.
Now the strange things is when i create a spreadsheet by myself (the owner is "me", my app doesn t find the file and return an error message.
I generated a key.p12 from my boss account and it still doesn't find the spreadsheet created by my boss, so from his point of view the owner is "me".
In conclusion:
I find the spreadsheet shared by my boss with my key and I can write in it.
I don't find the file created by me with my key.
My app doesn't find the file created by my boss with his key.
Here my code but i don't think the problem comes from here.
string keyFilePath; // found in developer console
string serviceAccountEmail;
if (test == true)
{
keyFilePath = #"C:\keyTEST.p12";
serviceAccountEmail = "me#developer.gserviceaccount.com";// found in developer console
}
else
{
keyFilePath = #"C:\key.p12";
serviceAccountEmail ="company#developer.gserviceaccount.com";
}
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) //create credential using certificate
{
Scopes = new[] { "https://spreadsheets.google.com/feeds/" } //this scopr is for spreadsheets, check google scope FAQ for others
}.FromCertificate(certificate));
credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait(); //request token
var requestFactory = new GDataRequestFactory("Some Name");
requestFactory.CustomHeaders.Add(string.Format("Authorization: Bearer {0}", credential.Token.AccessToken));
SpreadsheetsService myService = new SpreadsheetsService("Bank Details"); //create your old service
myService.RequestFactory = requestFactory; //add new request factory to your old service
myService.setUserCredentials(email, password);
// Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
SpreadsheetQuery query = new SpreadsheetQuery();
// Make a request to the API and get all spreadsheets.
SpreadsheetFeed feed = myService.Query(query);
SpreadsheetEntry fileEntry = feed.Entries.Cast<SpreadsheetEntry>().FirstOrDefault(entry => entry.Title.Text == spreadSheetName);
SpreadsheetEntry spreadsheet = (SpreadsheetEntry)fileEntry;
if (feed.Entries.Count == 0)
{
Console.WriteLine("None");
}
...
You need share in your sheet the e-mail "company#developer.gserviceaccount.com" or "me#developer.gserviceaccount.com".
Related
I'm trying to connect to SharePoint online in a console App and print the title of the site.
Its giving me the error : "The sign-in name or password does not match one in the Microsoft account system."
I have checked and made sure the username and password are 100% right.
I dont know what else to check
Heres my code:
private static void SPCredentialsConnect()
{
const string SiteUrl = "https://tenant.sharepoint.com/sites/mysite";
const string pwd = "appPassword";
const string username = "username#tenant.onmicrosoft.com";
SecureString securestring = new SecureString();
pwd.ToCharArray().ToList().ForEach(s => securestring.AppendChar(s));
ClientContext context = new ClientContext(SiteUrl);
context.Credentials = new SharePointOnlineCredentials(username, securestring);
try
{
var web = context.Web;
context.Load(web);
context.ExecuteQuery();
Console.WriteLine($"web title: {web.Title}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Have your issue fixed? “The sign-in name or password does not match one in the Microsoft account system” Error will occur sometimes and fixed after a while with nothing changed.
AppOnly Authentication for sharepointonline can't be registed in Azure Active Directory.
It should be register in
https://contoso.sharepoint.com/_layouts/15/appregnew.aspx
And grant permission in
https://contoso-admin.sharepoint.com/_layouts/15/appinv.aspx
You can refer to following document
https://learn.microsoft.com/en-us/sharepoint/dev/solution-guidance/security-apponly-azureacs
Consider using the PnP.Framework (a NuGet package), and use the AuthenticationManager object for SPO sites. This method bypasses MFA (which is mandatory in our organization, FWIW). You can find a lot more information and examples here, including steps on getting the client id and client secret for a site. Here is what we use to log into SPO sites:
using (ClientContext context =
new AuthenticationManager().GetACSAppOnlyContext(SiteUrl, clientID, clientSecret))
{
...
}
Also, once you connect, you should adjust the Context.Load to grab the title if you want to use that value right away. Here's what I used in my code:
context.Load(web, p => p.Id, p => p.Title);
context.ExecuteQuery();
Console.WriteLine($"Logged into source {web.Title} ({web.Id})");
Good luck!
Steve in Spain
I am trying to use the google drive sdk exmple for read spread sheet.
when I am opening the example I am getting this error: "unhandled excption has occured......... returned unexpected result"404"
I am doing the following things:
1) in the login section I am entering my user name and password correctly (validate it a couple of times that it is correct)
2) go to tab :"Selected SpreadSheet". then the error comes up
The problem you are experiencing is similar to this question: Google drive API to C#
You can no longer log into Google Spreadsheets with the old user credentials (username/password only). You need to use OAuth 2.0 now (which requires you to create an app and credentials at console.developers.google.com).
You can use the example below for the authentication logic, and use the logic in the logic found in this question to actually manipulate the file:
Accessing Google Spreadsheets with C# using Google Data API
Here is my answer to the linked question in case it gets deleted in the future:
This example requires you to use the following nuget packages and their dependencies:
Google.GData.Spreadsheets
Also, you must go to https://console.developers.google.com and register your application and create credentials for it so you can enter your CLIENT_ID and CLIENT_SECRET.
This is the documentation I used to put together this example: https://developers.google.com/google-apps/spreadsheets/
using System;
using System.Windows.Forms;
using Google.GData.Client;
using Google.GData.Spreadsheets;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
string CLIENT_ID = "YOUR_CLIENT_ID";
string CLIENT_SECRET = "YOUR_CLIENT_SECRET";
string SCOPE = "https://spreadsheets.google.com/feeds https://docs.google.com/feeds";
string REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
OAuth2Parameters parameters = new OAuth2Parameters();
parameters.ClientId = CLIENT_ID;
parameters.ClientSecret = CLIENT_SECRET;
parameters.RedirectUri = REDIRECT_URI;
parameters.Scope = SCOPE;
string authorizationUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
MessageBox.Show(authorizationUrl);
Console.WriteLine("Please visit the URL in the message box to authorize your OAuth "
+ "request token. Once that is complete, type in your access code to "
+ "continue...");
parameters.AccessCode = Console.ReadLine();
OAuthUtil.GetAccessToken(parameters);
string accessToken = parameters.AccessToken;
Console.WriteLine("OAuth Access Token: " + accessToken);
GOAuth2RequestFactory requestFactory =
new GOAuth2RequestFactory(null, "MySpreadsheetIntegration-v1", parameters);
SpreadsheetsService service = new SpreadsheetsService("MySpreadsheetIntegration-v1");
service.RequestFactory = requestFactory;
SpreadsheetQuery query = new SpreadsheetQuery();
SpreadsheetFeed feed = service.Query(query);
// Iterate through all of the spreadsheets returned
foreach (SpreadsheetEntry entry in feed.Entries)
{
// Print the title of this spreadsheet to the screen
Console.WriteLine(entry.Title.Text);
}
Console.ReadLine();
}
}
}
I'm trying to delete one or more videos using a simple C# app (I intend to use a Windows Service later) and I'm getting this error:
Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""
at Google.Apis.Requests.ClientServiceRequest`1.Execute() in c:\code\google.com\google-api-dotnet-client\default\Tools\Google.Apis.Release\bin\Debug\test\default\Src\GoogleApis\Apis\Requests\ClientServiceRequest.cs:line 93
Uploading videos works perfectly. For both operations, I use the same initialization method:
private static YouTubeService AuthorizeYoutubeService()
{
string serviceAccountEmail = "...#developer.gserviceaccount.com";
string keyFilePath = "Warehouse<...>.p12";
string userAccountEmail = "login#gmail.com";
if (!File.Exists(keyFilePath))
{
System.Windows.Forms.MessageBox.Show("Secret file not found!");
return null;
}
var scope = new string[] { YouTubeService.Scope.Youtube };
var cert = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
try
{
ServiceAccountCredential credential = new ServiceAccountCredential
(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = scope,
User = userAccountEmail
}.FromCertificate(cert));
var service = new YouTubeService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
ApplicationName = "warehouse"
});
return service;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return null;
}
}
The difference compared to simply uploading videos, is the defined Scope: YouTubeService.Scope.YoutubeUpload. When I try to delete a video using it, I get an insufficientPermissions (403) error.
So after looking in the documentation I've changed it to YouTubeService.Scope.Youtube.
Here's the code I'm trying to use:
var youtubeService = AuthorizeYoutubeService();
foreach (string id in deleteIds)
{
var videoDeleteRequest = youtubeService.Videos.Delete(id);
var result = videoDeleteRequest.Execute();
}
Where deleteIds is a list of 11 character strings containing IDs of existing videos.
I have YouTube Data API enabled in the developers console.
I've installed the API via NuGet, I don't think there's anything wrong with the packages.
I'm quite new to Google development, and all similar questions were about the calendar API.
I appreciate any help.
What I ended up doing is reseting the list of apps connected to the Google account and setting it up again from scratch. My app was added 2 times for some reason.
I have a working code using Excel Services published on on-premises SharePoint:
var _service = new ExcelService { UseDefaultCredentials = true };
Status[] _status;
var _sessionId = _service.OpenWorkbookForEditing("http://<sharepoint url>/<list>/<file>.xlsx", "en-US", "en-US", out _status);
ExcelService is a valid web reference pointing to http://<sharepoint url>/_vti_bin/excelservice.asmx
However, the same code doesn't work when using the Excel Services on SharePoint Online.
I am able to get the API version:
_service.GetApiVersion(out _status);
Excel Web Services (16.0)
But opening a workbook throws a SoapException:
We couldn't find the file you wanted.
I tried passing the credentials:
var _pass = new SecureString();
foreach (char _c in "<SP Online password>".ToCharArray()) { _pass.AppendChar(_c); }
var _cred = new SharePointOnlineCredentials("<SP Online login>", _pass);
var _service = new ExcelService { Credentials = _cred };
And the credentials seem to be valid, i.e. this code works:
// login test
using (ClientContext _sp = new ClientContext("<SP Online url>") { Credentials = _cred })
{
var _web = _sp.Web;
_sp.Load(_web);
_sp.ExecuteQuery();
Console.WriteLine(_web.Title);
}
What am I missing?
It seems it's an authentication issue but it's hard to tell since the error message is pretty opaque. How can I find out more details about the error?
Are Excel Services exposed only for specific licences?
Note, I am able to use Excel REST API but that doesn't work in my scenario (heavy editing).
Procedure
I'm going to:1. Get a OrgUnit from the Google Directory API 2. Read the OrgUnit and collect the required Data 3. Try to delete the OrgUnit I just collected.
This somehow results in a 404 [Not Found] Error Please keep in mind that the DirectoryService Class I am using, is working properly. I modified the code in this example to make it easy to read, for example: Exception handling is not included etc.
The API
using Google.Apis.Admin.Directory.directory_v1
1. Get a OrgUnit from the Google Directory API
DirectoryService directoryService = ServiceInitializers.InitializeDirectoryService();
OrgUnit oUnit = directoryService.Orgunits.List(Settings.customerId).Execute().OrganizationUnits.FirstOrDefault();
2.Read the OrgUnit and collect the required Data
string orgUnitPath = oUnit.OrgUnitPath;
3.Try to delete the OrgUnit I just collected
var orgUnitDeleteResult = directoryService.Orgunits.Delete(Settings.customerId, orgUnitPath).Execute();
The Exception
GoogleApiException was unhandledAn unhandled exception of type 'Google.GoogleApiException' occurred in Google.Apis.dll
Additional information: Google.Apis.Requests.RequestError
Org unit not found [404]
My reputation isn't high enough to add a comment to get clarification before posting an answer, so I'll have to make some assumptions here.
First assumption is that you're using a service account to access the API.
Second assumption is that you've got a certificate from your Google administrative control panel and that's all in order.
I had a similar issue when I was updating user accounts through the API, and what fixed it for me was having a directory administrator account act as a delegate for the service account.
Here's the code I use to initialize my Google Directory Service.
private static DirectoryService initializeGoogleDirectoryService()
{
try
{
String serviceAccountEmail = "your_service_account_email#developer.gserviceaccount.com";
var certificate = new X509Certificate2(#"your_certificate_name.p12", "your_secret", X509KeyStorageFlags.Exportable);
// For the service account to work, a user with admin privs must be assigned as the delegate.
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
// Change the scope here to the one you need to modify org units.
Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser },
User = "administrator_account#your_google_apps_domain.com"
}.FromCertificate(certificate));
// Create the service.
var service = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Your_Application_Name"
});
return service;
}
catch (Exception ex)
{
// Exception handling code below.
return null;
}
finally
{
}
}