c# Exceptions using Oauth2 with Google Drive API (using 4.0 .Net) - c#

I am using a code example at http://www.daimto.com/google-oauth2-csharp/ which would allow me to connect to the google drive api and get authorized using oauth2. I downloaded the .json file that has my client id and client secret and put it in the \bin\debug output folder (and a few other places out of desperation) and when the code progresses to opening that file, it causes an exception which says 'stream handle' threw an exception of type 'System.Object.DisposeException'
The code throws an exception here (at the credential line) when stepping through:
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
GoogleWebAuthorizationBroker.Folder = "Tasks.Auth.Store";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { DriveService.Scope.Drive,
DriveService.Scope.DriveFile },
"user",
CancellationToken.None,
new FileDataStore("Drive.Auth.Store")).Result;
}
This is probably the 4th or 5th code example I have tried, and none of them seem to work. It is quite disheartening.

I can see that that tutorial is very out of date. I am not sure why you are unable to use stream reader to read the file. But I think that you will find this code much cleaner and easer to understand.
string _client_id = "from apis console";
string _client_secret = "frome apis console";
string[] scopes = new string[] {DriveService.Scope.Drive,
DriveService.Scope.DriveFile };
// here is where we Request the user to give us access,
// or use the Refresh Token that was previously stored in %AppData%
UserCredential credential =
GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets {ClientId = _client_id,
ClientSecret = _client_secret },
scopes,
Environment.UserName,
CancellationToken.None,
new FileDataStore("Daimto.GooglePlus.Auth.Store")
).Result;
I will update that tutorial ASAP.

You are using an Async method to do your read. This is normally fine, but that means the code is still executing when you get to the end of your using statement. When the end bracket of the using is reached, the filestream is disposed while your async method is still trying to use it.
Try removing your using statement and instead disposing of the stream once your authorization is finished.

Related

Prompt user to always select Google account

I'm working on a .NET desktop app that needs interaction with Youtube APIs.
I'm following the first sample at https://developers.google.com/youtube/v3/code_samples/dotnet
My code runs fine, but I want to force the user to select the right Google account every time the application starts.
I've tried the following modification of the above sample:
UserCredential credential;
using (var stream = new FileStream("Assets\\client_secret.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecretsStream = stream,
Prompt = "select_account" // <-- This line does nothing...
},
new[] { YouTubeService.Scope.YoutubeReadonly },
"user",
CancellationToken.None
);
}
To my understanding, based on this old similar question, adding the Prompt = "select_account" parameter should do the trick but in reality it doesn't work as expected.
Infact it appears that the credentials are somewhat cached and the desired prompt never appears.
I've even tried to recompile the code in this way:
//omissis...
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets(), // <- no reference to the stream!
Prompt = "select_account"
},
and with my big surprise the app still work without any reference to the client_secret.json stream! Authentication is skipped completely after the user successfully logs in for the first time

Google OAuth2 Authorization On Linux Headless Server (.NET)

I'm curious how authentication on a Linux headless server works without an internet browser in C# for their Sheetsv4 API. All the code snippets they have on their getting started page have reference to GoogleWebAuthorizationBroker, which doesn't work without a web-browser. I've seen references to GoogleAuthorizationCodeFlow, but I'm not sure if this is what I'm looking for - nor how you would be intended to use it. My current code is bellow-
UserCredential Credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(Stream).Secrets,
new string[1] { SheetsService.Scope.SpreadsheetsReadonly },
"user",
CancellationToken.None,
new FileDataStore(GreetFurConfiguration.TokenFile, true)
).Result;
What I would want is for a link to be generated and, from there, to be able to paste the token into the console, as this is how other Google APIs handle this authentication (Go, NodeJS) which I have used before and seem to work well.
If there is any better way to handle this authentication though that is more suitable for a .NET workflow, that would be suitable as well. I can't manage to find any examples of how you'd get a OAuth2 token for the life of me though without having access to a web browser on the host machine.
EDIT: I'd be looking for https://github.com/googleapis/google-api-dotnet-client/blob/master/Src/Support/Google.Apis.Auth/OAuth2/PromptCodeReceiver.cs
However, I can't find any documentation on how to use this class.
The GoogleWebAuthorizationBroker.AuthorizeAsync allows you to send which code receiver you want The one you are looking for is PromptCodeReceiver.
private const string PathToCredentialFile = "/home/linda/development/creds/client.json";
static async Task Main(string[] args)
{
var scope = new[] {AnalyticsReportingService.Scope.AnalyticsReadonly};
var credPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
await using (var stream = new FileStream(PathToCredentialFile, FileMode.Open, FileAccess.Read))
{
// Requesting Authentication or loading previously stored authentication for userName
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
scope,
"userName",
CancellationToken.None,
new FileDataStore(credPath, true),
new PromptCodeReceiver()).Result;
Console.WriteLine($"AccessToken: {credential.Token.AccessToken}");
}
Output:
Please visit the following URL in a web browser, then enter the code shown after authorization:
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&response_type=code&client_id=1XXXXX.apps.googleusercontent.com&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fanalytics.readonly
Please enter code:
4/1AY0e-g6L3ASB0lEhWNkh4lDc4nl5k0xV177o38taWFzEzKBv3H24ZC4zQAM
Access toekn: ya29.a0AfH6SMB8ZhpZJgKkpMfbiflxeOF_o6Gzs6fxIuPI25Vewbp7NgVAfJp8EX6K5zgielRrYaSFjqwKIY8MoCuCDbPeF5-2w6_WRnauWqtpleqk2zjqmkHgpfNwbpO8n7VmHVSF9Mgn3YOZRl

Opening OAuth2 Authorization URL in a browser control

I am trying to learn about the Google's Drive API while I am writing a little program. I am using GoogleWebAuthorizationBroker class for asking the user to give the app permissions, but the drawback is that it is automatically opening a new browser tab in Chrome (as an example):
const string ApplicationName = "TestApp";
string[] scopes = { DriveService.Scope.Drive };
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/drive-dotnet-quickstart");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
I would like to know if there is a way to get the AuthorizationURL so I can show a browser dialog with it, and therefore get the respective token.
How can that be done? Thanks in advance.
Currently the way the client library is written it will automatically open it in the default browser.
There is an issue request already for this feature. GoogleWebAuthorizationBroker in embedded browser? #547
Answer: There is currently no way to get the Authorization url so that you can sow the dialog on your own. The client library is an open source project so you can add it.

Google Coordinate API authentication offline

Trying to authenticate the Google coordinate api. Tried the Service acount authentication usisng service account and posted stack flow with this question. Found this anwer and quite describes my question.
What the problem now is the library used is deprecated. Not able to execute the solution said.
var auth = new OAuth2Authenticator<WebServerClient> (provider, GetAuthorization);
// Create the service.
var service = new CoordinateService(new BaseClientService.Initializer()
{
Authenticator = auth
});
can anybody suggest a way to achieve the above code. I have installed the new version for Google APIs OAuth2 Client Library. But didn't found any similar code.
I am able to do the read the api using the below code snippet
using Google.Apis.Auth.OAuth2;
using Google.Apis.Coordinate.v1;
using Google.Apis.Coordinate.v1.Data;
using Google.Apis.Services;
using (var stream = new FileStream(System.Web.HttpContext.Current.Server.MapPath(#"../client_secret.json"), FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
new[] { CoordinateService.Scope.Coordinate },
"user", CancellationToken.None);
}
// Create the service.
var service = new CoordinateService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "test",
});
//builds with time last day 12 am
var locationReq = service.Location.List(teamId, workerMail, (ulong)DateTime.Today.AddDays(-1).ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
var locationResult = locationReq.Execute();
but this method reuires a redirection for the first time. I can't do that in my scenario. so need an offline solution.
Need to authenticate using a browser instance first and can reuse same "refresh token" for all other requests. We can provide a custom folder location to store the "auth token" and the library will use stored token from that folder. Modified source code pasted below:
using (var stream = new FileStream(#"client_secret.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
new[] { CoordinateService.Scope.Coordinate },
"user", CancellationToken.None,new FileDataStore(folder));
}
MG
It looks like you are using a very old version of the library (pre GA).
I recommend you to download the latest Coordinate API, which is available in NuGet - https://www.nuget.org/packages/Google.Apis.Coordinate.v1/.
Then, follow the get started and the OAuth 2.0 pages. You should find all the right documentation there, if something is missing - let us know. Open an issue in our issue tracker.

youtube api token upload video

I am retriving a token through an website, then I save the token, and refresh token in a database. Then I am writing .net program that uploads video's located on our server to youtube. My problem is to get the program I am making, use the stored token. I am using one of google's examples to upload the video. But the program should use the already saved token, instead os asking for new credentials.
The current code is this.
UserCredential credential;
//credential.UserCredential(,"",)
using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
// This OAuth 2.0 access scope allows an application to upload files to the
// authenticated user's YouTube channel, but doesn't allow other types of access.
new[] { YouTubeService.Scope.YoutubeUpload },
"user",
CancellationToken.None
);
}
Console.WriteLine("HER");
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
});
So instead I would like to use an already saved token.
Any help, or a pointer in the right direction would be great. Thanks.
You would use GoogleAuthorizationCodeFlow instead of GoogleWebAuthorizationBroker in order to use the refresh token. See the answer here.

Categories