I have an app that allow me to read the data from Google Spreadsheet using API Key. I just make HTTP GET to this address and get a response with data.
https://sheets.googleapis.com/v4/spreadsheets/18soCZy9H4ZGuu**********BeHlNY1lD8at-Pbjmf8c/values/Sheet1!A1?key=AIzaSyAYJ***********pB-4iKZjYf4y0vhXP8OM
But when I try to do same to write data using HTTP PUT to address
https://sheets.googleapis.com/v4/spreadsheets/18soCZy9H4ZGuu**********BeHlNY1lD8at-Pbjmf8c/values/Sheet1!A4?valueInputOption=RAW?key=AIzaSyAYJ***********pB-4iKZjYf4y0vhXP8OM
its gives me 401 error.
Code to make PUT request:
using (WebClient wc = new WebClient())
{
byte[] res = wc.UploadData(link, "PUT", Encoding.ASCII.GetBytes(textBox1.Text));
MessageBox.Show(Encoding.Default.GetString(res));
}
Also spreadsheet is fully public with permission to read and write by anyone without auth. My guess is that I can't use API Key to write data to spreadsheet, and only way to do this is using OAuth.
UPDATE:
So i've just tryed Google.Apis.Sheets.v4 to write values, and now i'm almost 100% sure that API Key can't be used to write data to Google Spreadsheet. Well, then I'll use OAuth 2.0.
Well, maybe you are correct and the problem here is the API_KEY itself.
If you check the Sheets API documentation, it is stated that every request your application sends to the Google Sheets API needs to identify your application to Google. There are two ways to identify your application: using an OAuth 2.0 token (which also authorizes the request) and/or using the application's API key. Here's how to determine which of those options to use:
If the request requires authorization (such as a request for an individual's private data), then the application must provide an OAuth 2.0 token with the request. The application may also provide the API key, but it doesn't have to.
If the request doesn't require authorization (such as a request for public data), then the application must provide either the API key or an OAuth 2.0 token, or both—whatever option is most convenient for you.
So meaning either the OAuth 2.0 token or API key will work in your case since the file is public. But the problem is in the PUT request that you are doing, we can assume here that the API key is not working with it. But, we have alternatives for it, and that is the OAuth.
I also found here a related SO question that might help you.
For anyone still hoping for a simple answer, it seems there won't be one - any writing to a sheet, irrespective of the sheets permissions, will require OAuth2:
'This is intentional behavior. While public sheets are anonymously readable, anonymous edits aren't currently supported for a variety of reasons.
In this context, "anyone" == anyone with a google account.' HERE
One option that wasn't mentioned here is to use a service account instead. Service accounts are like users, but without being attached to a person. Instead, they're attached to a project.
Service accounts have an email address as well as a private key. Both can be used to create a JWTClientAuth, and this can be used to authenticate the API while it's being instantiated or to authenticate each and every request.
The advantage of the service account is that it works like an API KEY -- no need to ask a user to copy a URL to the browser and then copy a code back into the application -- but because it can act as an authenticated user, the service account email address can be added to the Google Sheet as an editor. With this in place, the application has full write access to the sheet but without having to deal with authorization codes and refresh tokens and copy/pasting.
You can see a Python example, Python With Google Sheets Service Account Step By Step, and a Node.js example, Accessing Google APIs Using Service Account in Node.js. I followed these examples to get setup.
Since you're using C#, you may find Writing to Google Sheets API Using .NET and a Service Account to be helpful.
This method reads the service account credentials from the JSON file to then instantiate the SheetsService:
private void ConnectToGoogle() {
GoogleCredential credential;
// Put your credentials json file in the root of the solution and make sure copy to output dir property is set to always copy
using (var stream = new FileStream(Path.Combine(HttpRuntime.BinDirectory, "credentials.json"),
FileMode.Open, FileAccess.Read)) {
credential = GoogleCredential.FromStream(stream).CreateScoped(_scopes);
}
// Create Google Sheets API service.
_sheetsService = new SheetsService(new BaseClientService.Initializer() {
HttpClientInitializer = credential, ApplicationName = _applicationName
});
}
Afterwards, you can use the Google Sheets .NET Client Library to write the data.
Related
I want my users to be able to upload videos to MY YouTube channel under MY YouTube account. Hence I don't really want or need them to authenticate (OAuth) as themselves.
I've seen the examples here: https://developers.google.com/youtube/v3/code_samples/dotnet
All of the code examples I find seem to use OAuth and client secrets to authenticate. Can anybody point me in the direction of a nice tutorial/sample whereby I can upload a video to MY Channel as MYself (using an API key?)?
Thanks.
UPDATE
Well....I'm not even sure if what I've done is right....but here is what I've done:
Went to Credentials for my project:
https://console.developers.google.com/apis/credentials
Created 2 OAuth credenials - one was Web Application and one was Other. I downloaded the JSON for these and added them to my project so I could test each one.
I enabled the YouTube data API here:
https://console.developers.google.com/apis/api/youtube.googleapis.com/overview
I largely took the .Net upload example from here:
https://developers.google.com/youtube/v3/code_samples/dotnet
I also installed the Nuget package for the YouTube API v3
before "var youtubeService =..." I added this:
// This bit checks if the token is out of date,
// and refreshes the access token using the refresh token.
if (credential.Token.IsExpired(SystemClock.Default))
{
if (!await credential.RefreshTokenAsync(CancellationToken.None))
{
Console.WriteLine("No valid refresh token.");
}
}
also created the following class - again, I obtained it from another StackOverflow post - with the aim of creating an offline access token??
public class OfflineAccessGoogleAuthorizationCodeFlow : GoogleAuthorizationCodeFlow
{
public OfflineAccessGoogleAuthorizationCodeFlow(GoogleAuthorizationCodeFlow.Initializer initializer) : base(initializer) { }
public override AuthorizationCodeRequestUrl CreateAuthorizationCodeRequest(string redirectUri)
{
return new GoogleAuthorizationCodeRequestUrl(new Uri(AuthorizationServerUrl))
{
ClientId = ClientSecrets.ClientId,
Scope = string.Join(" ", Scopes),
RedirectUri = redirectUri,
AccessType = "offline",
ApprovalPrompt = "force"
};
}
}
So I've tested it, and the upload eventually 'seems' to work, however:
The code never returns back to the View from await videosInsertRequest.UploadAsync(); and just seems to hang....UPDATE - Fixed. See here: https://www.codeproject.com/Questions/1087360/Youtube-data-API-for-uploading-videos-not-working
The video never actually appears in my channel - i have a feeling YouTube ban it before it's even uploaded? (it's just a test video - nothing sinister - could that be why?)
I have no idea if I am still doing this right.
Any more advice please? I still struggle to believe nobody has a working example of what I'm after. I can't believe that a user....uploading a video to my web server.....and then uploading to my own channel is so difficult!!
First off: It is impossible to upload videos with API keys.
From a technical point of view, API keys are not tied to a specific YouTube channel, but to a Google Cloud Console project. That means even if YouTube allowed API keys as authentication for uploading videos, they wouldn't know which channel to upload to.
For all write actions (e.g. uploading videos), proper authentication via OAuth 2.0 is required. Therefore, there are no tutorials that show how to upload using an API key.
As #Gusman said, you would need to let your users upload to your server, and then your server uploads to YouTube using OAuth credentials.
Regarding "'Installed Application' no longer seems to exist...":
The way you work with API keys and OAuth client IDs/secrets in your code has stayed exactly the same. Google just changed how you create and restrict access to keys in the Cloud Console.
I encourage you to familiarize yourself with the concept of server-side apps that use the YouTube API.
EDIT: to clarify the workflow
You set up a Cloud Console project and an OAuth client ID.
You give your permission to your application that it may upload videos to your channel. Your application will receive tokens (access token and refresh token) as a result.
Users of your application upload their videos to your application server.
Your application takes the user's video (which is now locally on your server) and the tokens from step 2 and uploads the video to YouTube with those tokens.
You must use oAuth, but what you want to skip is the user authentication step.
See this SO answer here
You need to obtain a refresh token and store that in your code along with the OAuth Key and Secret.
As for your "banned" video. If the video was uploaded as 'unlisted' it will not show up until you navigate to your Creator Studio -> Videos list
I'm running a process without UI that retrieves uploaded videos from youtube. On a develpement machine it authenticates on user behalf and it works.
The problem is when process is running on a server: browser window doesn't fire for user to let use his account (it should only require to do it once).
Event viewer shows no errors whatsoever. Service accounts doesn't seem to work with youtube, with API key is too less permissions and
oath is the only way to authenticate and get broadcasted videos. Or am I wrong?
So the question is: How to run a service as a single user and retrieve his videos without UI?
private async Task Run()
{
try
{
UserCredential credential;
using (var stream = new FileStream(StartPath + "\\client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { YouTubeService.Scope.YoutubeReadonly, YouTubeService.Scope.Youtube },
"user",
CancellationToken.None,
new FileDataStore("Store")
);
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = this.GetType().ToString()
});
....
}
I have also tried:
String serviceAccountEmail = "e-mail";
var certificate = new X509Certificate2(HostingEnvironment.MapPath("~/Content/key.p12"), "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { YouTubeService.Scope.Youtube, YouTubeService.Scope.YoutubepartnerChannelAudit, YouTubeService.Scope.YoutubeUpload }
}.FromCertificate(certificate));
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "api",
});
The YouTube Data API lets you incorporate functions normally executed on the YouTube website into your own website or application. The lists below identify the different types of resources that you can retrieve using the API. The API also supports methods to insert, update, or delete many of these resources.
This reference guide explains how to use the API to perform all of these operations. The guide is organized by resource type. A resource represents a type of item that comprises part of the YouTube experience, such as a video, a playlist, or a subscription. For each resource type, the guide lists one or more data representations, and resources are represented as JSON objects. The guide also lists one or more supported methods (LIST, POST, DELETE, etc.) for each resource type and explains how to use those methods in your application.
The following requirements apply to YouTube Data API requests:
Every request must either specify an API key (with the key parameter) or provide an OAuth 2.0 token.
Your API key is available in the Developer Console's API Access pane for your project.
You must send an authorization token for every insert, update, and delete request. You must also send an authorization token for any request that retrieves the authenticated user's private data.
In addition, some API methods for retrieving resources may support parameters that require authorization or may contain additional metadata when requests are authorized. For example, a request to retrieve a user's uploaded videos may also contain private videos if the request is authorized by that specific user.
The API supports the OAuth 2.0 authentication protocol. You can provide an OAuth 2.0 token in either of the following ways:
Use the access_token query parameter like this: ?access_token=oauth2-token
Use the HTTP Authorization header like this: Authorization: Bearer oauth2-token
Complete instructions for implementing OAuth 2.0 authentication in your application can be found in the authentication guide.
So I've managed to make a work around that situation by creating console application program that does the thing.
Authentication mechanism moved into console application and passed the results to the service. In a service made a call into that application every n seconds. This solution worked like a charm. Ugly one, but it worked. Now i can give application access to profile data and use it where I want to.
If anyone will have a better solution I would be glad to read it.
I've created a web application that uses the OAuth authentication and universal connectors as explained in this tutorial, and started to fiddle around a little to add support for other providers like Yahoo and LinkedIn. So the authentication part works and users are created in the asp.net Membership provider. Also, all the providers return the accesstoken which I supposedly can use to retrieve more information regarding the user.
I'd really like to acquire the profile image, but it seems every provider has a different way of requesting this information. Twitter even describes a way to authorise every request by changing the HTTP header information.
Whilst reading this information on the websites of the various providers I was wondering whether this functionality isn't also already included somewhere in DotNetOpenAuth.AspNet or Microsoft.AspNet.Membership.OpenAuth implementation.
How can I use DotNetOpenAuth.AspNet and/or Microsoft.AspNet.Membership.OpenAuth to request the profile image of the loggedin user using the just acquired accesstoken?
UPDATE in response to Leo's answer
I use the following code to make a call on LinkedIn's API.
string accessToken = extraData["accesstoken"]; // Extra Data received from OAuth containing the accesstoken.
WebRequest request = WebRequest.Create("https://api.linkedin.com/v1/people/~:(id,first-name,last-name,date-of-birth,email-address,picture-url)?oauth2_access_token=" + accessToken);
using (WebResponse response = request.GetResponse())
{
// do something with response here.
}
Error message is "The remote server returned an error: (401) Unauthorized.".
What am I doing wrong?
The answer is simple...you can't use any of these. These are wrappers of OAuth and OAuth only specifies how you can authenticate a user. Now, to request the user's profile photo you will need to use the external provider's own API and you will need most likely a valid access token. So, you will need to use one of these implementations of OAuth to authenticate a user and the recieve an access token, store the access token somewhere (usually a cookie) and then use the access token to make sub-sequent calls to the provider's APIs. Examples and links....
Facebook's Graph API allows you to retrieve users profiles
https://developers.facebook.com/docs/graph-api/quickstart/
notice that all examples in the link above will require you to include the access token in a parameter named access_token, for example
https://graph.facebook.com/me?method=GET&format=json&suppress_http_code=1&access_token={your-access-token}
Google...
https://www.googleapis.com/oauth2/v3/userinfo?access_token={your-access-token}
LinkedIn...
https://api.linkedin.com/v1/people/~:(id,first-name,last-name,date-of-birth,email-address,picture-url)?oauth2_access_token={your-access-token}
You can get more specific information from these providers' websites
Let me know if you have any other doubts I might be able to help you since I have implemented stuff like these before.
Cheers, Leo
I'm trying to upgrade may program to support the new oAuth that Google uses in the AdWords.
I've my on-line part, which work fine, and get the access tokens (token, secret and consumer key).
My problem is when I try to make a soap request later with those credentials.
A. Which information do I need to save from the OnLine part? so far I save only the accessToken and the accessTokenSecret.
B. How do I use the accessToken, accessTokenSecret and what ever else I've saved in order to make a SOAP requests?
Some info on my process:
Not using the Client Library from Google (too much over head, and so far I didn't needed them)
Using the auto-generated code using VS2005 WSDL on the services I'm using.
C#
The problem is that what you're trying to do is a bit involved. It's got more to do with the oAuth process itself than the AdWords API implementation. I think that this is a case where it would be very beneficial to use the client library.
You actually need to use your token and consumer key to sign the request. This can either be done using RSA-SHA1 or RSA-HMAC; in the first instance you sign it with a private key file and upload the public key to Google; for RSA-HMAC you just use the token and consumer secrets instead of the public/private key.
You can find out more about doing this here, but I would recommend just using Google's implementation unless you're interested in the internals of oAuth. I tried it myself a while ago and found it quite complicated.
Hy guys, we are developing a system which will provide users with access to Google Analytics. I'm trying to implement it in the way so user don't need to enter their Google login credentials on our site, so trying to get it work using their login.
I have a solution which gets analytics using user's email and password. I'm looking for a solution which will not require user's email and password but can not find anything.
How can it be done? any advices or links will be appreciated.
thanks
Ok, guys, after a few days of struggle I finally figured this out. There is no documentation on the Internet and people who had done it before did not want to share their success by some reason. I found this discussion which helped me.
To make it work you will need DotNetOpenAuth from http://www.dotnetopenauth.net/ and gdata from http://code.google.com/p/google-gdata/
so
using DotNetOpenAuth.ApplicationBlock;
using DotNetOpenAuth.OAuth;
using Google.GData.Client;
using Google.GData.Analytics;
In DotNetOpenAuth there is sample project named OAuthConsumer which you need.
Change it to requiest authorization for Analytics:
GoogleConsumer.RequestAuthorization(google, GoogleConsumer.Applications.Analytics);
This will get you Token and Token secret.
You can use them like this:
GOAuthRequestFactory requestFactory = new GOAuthRequestFactory("cp", TokenManager.ConsumerKey); //ConsumerKey actually is the name of web application
requestFactory.ConsumerKey = TokenManager.ConsumerKey;
requestFactory.ConsumerSecret = TokenManager.ConsumerSecret;
requestFactory.Token = AccessToken;
requestFactory.TokenSecret = TokenManager.GetTokenSecret(AccessToken);
requestFactory.UseSSL = true;
AnalyticsService service = new AnalyticsService(requestFactory.ApplicationName); // acually the same as ConsumerKey
service.RequestFactory = requestFactory;
const string dataFeedUrl = "https://www.google.com/analytics/feeds/data";
DataQuery query1 = new DataQuery(dataFeedUrl);
This service you can use like here or here
And the last thing, you WILL NOT be available to try and test it on localhost so you will need a domain which MUST be registered with Google here in order to get consumer key and secret
There's a .NET/C# class for Google Data authentication that can be used to access the Google Analytics Data Export API (since the API is part of the Google Data standard, though you might need to make Google Analytics specific adjustments.)*
The authentication is best managed by creating a Google Registered Application, as this allows you to make the authentication without security warnings (and, for that matter, security lapses).
There are three forms of supported authentication; the 'secure'/passwordless ones are OAuth and AuthSub (which is the Google-proprietary version of OAuth); the hardcoded username and password version is referred to by Google as 'ClientLogin', and is not considered secure or ideal for multiple-user applications.
*(Since you tagged the question .netc#)
Edit: More details on using AuthSub or OAuth with the .NET library:
AuthSubSupport: http://code.google.com/p/google-gdata/wiki/AuthSubSupport
Code Samples on how to use the libraries for OAuth authentication: http://code.google.com/apis/gdata/docs/auth/oauth.html#2LeggedOAuth (Click the .NET tab).
Basics of working with OAuth are here: http://code.google.com/apis/accounts/docs/OpenID.html#working
Authenticating with OAuth: http://code.google.com/apis/accounts/docs/OAuth.html
After you authenticate a user with OAuth, you will have the request token that works like the one you get back from Google's login API. From there, it should be the same as username/password.
I don't think you need to mess with OAuth.
The google analytics api lets you pass credentials. Just start from this data feed example.
http://code.google.com/p/google-gdata/source/browse/trunk/clients/cs/samples/Analytics_DataFeed_Sample/dataFeed.cs
// Configure GA API and do client login Authorization.
AnalyticsService asv = new AnalyticsService("gaExportAPI_acctSample_v2.0");
asv.setUserCredentials(clientUser, clientPass);
Download the client library here
http://code.google.com/apis/analytics/docs/gdata/gdataLibraries.html
To get a feel for data queries, play with this and then copy the values into the example above
http://code.google.com/apis/analytics/docs/gdata/gdataExplorer.html