Does anyone have a simple example how to use Google.Apis.Auth.OAuth with C# Webforms? I can only find the MVC ones.
I struggled for a while converting an original sample for a console application - it is really intended to show how your app can access the users' own google sheets.
https://developers.google.com/sheets/api/quickstart/dotnet
There is an MVC based example - which doesn't lend itself very well to webforms - this however is again really for when the website is accessing any user's data
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#web-applications-aspnet-mvc
So part of the process for both of these - is that you get sent to Google's API to grant access to the user's data e.g. access to the Google sheet that you own. After granting access it goes back to the return url you specify.
The console example opens a browser for the granting access bit.
Once you have granted access a file is saved which stores this permission and it doesn't need to ask for it again.
I converted the console app code to run in a webform but this required that I copy the credential file (that I had generated using the console app sample). It is not possible to generate the credential file as it tries to get IIS to launch a browser to get authority which the IIS user does not have permission to do (and wouldn't work in production anyway). If you have copied the file to somewhere IIS can view it it will work though (if the credentials file exists it skips opening a browser to get permission).
Here is my sample for this (code behind for webform):
Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Sheets.v4
Imports Google.Apis.Sheets.v4.Data
Imports Google.Apis.Services
Imports Google.Apis.Util.Store
Imports System.Collections.Generic
Imports System.Threading
Private Sub btnImportData_Click(sender As Object, e As EventArgs) Handles btnImportData.Click
Dim ApplicationName As String = "Google Sheets API .NET Quickstart"
'Dim credPath As String = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal)
'credPath = Path.Combine(credPath, ".credentials/sheets.googleapis.com-dotnet-quickstart.json")
Dim credPath As String = Server.MapPath("~/YourPathToCredentials/google-api-credentials")
Dim CS As New ClientSecrets With {
.ClientId = "-- YOUR CLIENT ID --",
.ClientSecret = "-- YOUR CLIENT SECRET --"
}
'Dim Scopes As String() = {SheetsService.Scope.SpreadsheetsReadonly}
Dim Scopes As IEnumerable(Of String) = {SheetsService.Scope.Drive}
'Dim DataStore = New FileDataStore("Drive.Api.Auth.Store")
Dim credential As UserCredential = GoogleWebAuthorizationBroker.AuthorizeAsync(CS, Scopes, "user", CancellationToken.None, New FileDataStore(credPath, True)).Result
Diagnostics.Debug.WriteLine("Credential file saved to: " & credPath)
Dim service = New SheetsService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential,
.ApplicationName = ApplicationName
})
'Glossary Spreadsheet used as data repository for Glossary BETA Google Forms prototype
Dim spreadsheetId As String = "-- YOUR GOOGLE SHEET ID --"
Dim range As String = "Form responses 1!A2:G"
Dim request As SpreadsheetsResource.ValuesResource.GetRequest = service.Spreadsheets.Values.[Get](spreadsheetId, range)
Dim response As ValueRange = request.Execute()
Dim values As IList(Of IList(Of Object)) = response.Values
If values IsNot Nothing AndAlso values.Count > 0 Then
Diagnostics.Debug.WriteLine("Category, Term, Definition")
For Each row In values
Diagnostics.Debug.WriteLine("{0}, {1}, {2}", row(3), row(1), row(2))
Next
Else
Diagnostics.Debug.WriteLine("No data found.")
End If
End Sub
A far more relevant and easier approach is a completely different type which is designed for server-to-server communications i.e. webform code-behind to Google API.
For this you need a "service account" - these credentials are created on the api backend and can then be used by a web application in code - which was exactly the use case that I was looking for (always the same data store owned by me in Google Sheets).
https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#service-account
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
So here is my example using a Google Service account.
Note - I created a Service Account on the Google API Console - this generates an email address for this back-office account - I had to give permission to this email for the sheet I was interested in. The code examples on Google were for the older P12 format - whereas the API console recommends the newer JSON format. My example code has been modified to use the more modern JSON format. When you create the service account it gives you a file to download make sure you save a copy somewhere safely as you will not be able to regenerate it. Its not the end of the world if you do but you won't be able to use that account again you will have to make a new one and give that one permissions.
Imports System.Data
Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Sheets.v4
Imports Google.Apis.Sheets.v4.Data
Imports Google.Apis.Services
Imports Google.Apis.Util.Store
Imports System.Collections.Generic
Imports System.Threading
Imports System.IO
Public Sub ImportGlossaryGoogleSheetData_ServiceAccount()
Diagnostics.Debug.WriteLine("=====================================")
Diagnostics.Debug.WriteLine("Import Glossary using Service Account")
Diagnostics.Debug.WriteLine("=====================================")
Dim credPath As String = Server.MapPath("~/YourPathToCredentials/google-api-credentials/credentialfile.json")
Dim credential As ServiceAccountCredential
Using stream As New FileStream(credPath, FileMode.Open, FileAccess.Read, FileShare.Read)
credential = GoogleCredential.FromStream(stream).CreateScoped({SheetsService.Scope.Drive}).UnderlyingCredential
End Using
Dim service = New SheetsService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential,
.ApplicationName = "YOUR APP NAME"
})
'Glossary Spreadsheet used as data repository for Glossary BETA Google Forms prototype
Dim spreadsheetId As String = "-- YOUR GOOGLE SHEET ID --"
Dim range As String = "Form responses 1!A2:G"
Dim request As SpreadsheetsResource.ValuesResource.GetRequest = service.Spreadsheets.Values.[Get](spreadsheetId, range)
Dim response As ValueRange = request.Execute()
Dim values As IList(Of IList(Of Object)) = response.Values
If values IsNot Nothing AndAlso values.Count > 0 Then
Diagnostics.Debug.WriteLine("Category, Term, Definition")
For Each row In values
Diagnostics.Debug.WriteLine("{0}, {1}, {2}", row(3), row(1), row(2))
Next
Else
Diagnostics.Debug.WriteLine("No data found.")
End If
End Sub
I hope this explains what I discovered about the different approaches given by google:
OAuth - a generic approach to allow your code permission to view the user's data e.g. Your website looking at data in the user's Google Sheet.
Service Account - server to server access to Google API - e.g. your website looking at specific data using Google API i.e. hard coded to look at data that you own and generate credentials for in Google's API backend.
It's been a while but I thought this might be useful for someone:
GoogleFlowMetaData:
public class GoogleFlowMetaData
{
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "your client ID",
ClientSecret = "your client secret"
},
Scopes = new[] { CalendarService.Scope.Drive/*or any service you want*/ },
DataStore = new FileDataStore("Drive.Api.Auth.Store")
});
public IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
AuthorizationCodeApp:
public class AuthorizationCodeApp : AuthorizationCodeWebApp
{
private readonly GoogleFlowMetaData flowData;
private readonly string redirectUri;
private readonly string state;
private readonly string userID;
public GoogleFlowMetaData FlowData { get { return flowData; } }
public AuthorizationCodeApp(GoogleFlowMetaData flowData, string redirectUri, string state, string userID):base(
flowData.Flow,redirectUri,state)
{
this.redirectUri = redirectUri;
this.state = state;
this.userID = userID;
}
public Task<AuthResult> AuthorizeAsync(CancellationToken taskCancellationToken)
{
return base.AuthorizeAsync(userID, taskCancellationToken);
}
}
now to run an Async task wherever you may want to define something like:
public async Task<string> IndexAsync(CancellationToken cancellationToken)
{
var result = await new AuthorizationCodeApp(new GoogleFlowMetaData(), "http://localhost:4356/API/GAuth","","beebee").
AuthorizeAsync(cancellationToken);
if (result.Credential != null)
{
var service = new DriveService(new BaseClientService.Initializer
{
// YOUR CODE SHOULD BE HERE..
});
}
else
{
return result.RedirectUri;
}
}
to call the above function asynchronously use something like:
var cancelToken = new CancellationTokenSource();
var z = Task.Factory.StartNew(() => IndexAsync(cancelToken.Token));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With