1

My need is very specific. I need to access a directory on Google Drive that is a shared folder. The only thing in it will be empty form documents and spreadsheet templates. There is nothing of value in the folder, and it is used internally only. So, I can be very optimistic WRT security concerns. I just need access.

I am extending an existing ERP system that runs as an IIS application. My customization is .NET/C# project that extends the ERP's .NET classes. I cannot implement a login/auth system because one already exists for the ERP.

I did the .NET quickstart, but of course that is a console app, and will not work when I move it to IIS. The suggestion to follow the standard MVC model doesn't work for me -- adding a second web site/page is needlessly complicated for my needs.

My question is: How can I authorize access to a Google Drive that

A) Runs within IIS B) Does not require a separate ASP Web Application to implement MVC for authorization.

=============================

Similar to issues in: Google API Fails after hosting it to IIS

MarkJoel60
  • 537
  • 2
  • 6
  • 24

2 Answers2

1

you could use OAuth authorization with your asp.net application:

Create Web Server client_secret.json.by using GetAuthorizationUrl() create url for get toke temporary token.Redirect to GoogleCallback() and get refresh and access tokens using ExchangeAuthorizationCode().Save them to the file "~/Resources/driveApiCredentials/drive-credentials.json/Google.Apis.Auth.OAuth2.Responses.TokenResponse-{account}".Use this saved tokens.

you could refer to the below link for more detail:

https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#web-applications-aspnet-mvc

Google Drive API upload Fails after hosting it to IIS. showing the error as Failed to launch the Browser with

Google Drive API not uploading file from IIS

Google Data API Authorization Redirect URI Mismatch

Jalpa Panchal
  • 8,251
  • 1
  • 11
  • 26
0

Jalpa's answer was not what I was looking for, nor was anything referenced in any of the links.

I'm going to put my answer here, because it is what I needed, and it might be useful to others.

First the overview

Google's QuickStart for .NET only shows the console based solution. As many have discovered, this does not work when you switch to an IIS based solution. It is almost as if the API deliberately defeats your attempts to do so. It simply will not allow you to use a token created for a local application using GoogleWebAuthorizationBroker.AuthorizeAsync -- it will error even if a browser isn't needed. (ie the token hasn't expired, so it won't need the browser to authenticate anything.)

Trying to run a refresh authorization gives you a token, but not a service. And even if the token is valid, you still can't use AuthorizeAsync to get your service from an IIS application (see above)

This is how I handle this:

  1. Do the quick start and run the authorization that pops up the local browser and allows you to login and authenticate.
  2. It creates a local folder(token.json), where it puts a token file (Google.Apis.Auth.OAuth2.Responses.TokenResponse-user) It's just a json file. Open it in notepad++ and you will find the fields:
  • "access_token": "token_type": "expires_in": "refresh_token":
    "scope": "Issued": "IssuedUtc":

You need the refresh_token. I simply combined that with the initial credentials file I downloaded from the Google API Console (i.e. "credentials.json") and named it "skeleton_key.json"

This file is all you will need to generate valid tokens forever.

I have 2 classes I use for this. First the class that creates the Drive Service:

public class GDriveClass
{
    public String LastErrorMessage { get; set; }
    static string[] Scopes = { DriveService.Scope.Drive }; // could pull this from skeleton_key
    static string ApplicationName = "GDrive Access"; // this is functionally irrelevant
    internal UserCredential usrCredentials;
    internal Google.Apis.Drive.v3.DriveService CurrentGDriveService = null;
    internal String basePath = ".";  // this comes in from calling program 
                                     // which uses HttpContext.Current.Server.MapPath("~");

    public GDriveClass(string logFileBasePath)
    {
        basePath = logFileBasePath;
        LastErrorMessage = "";
    }

    #region Google Drive Authenticate Code
    public bool AuthenticateUser(string FullTokenAccessFileName)
    {
        UserCredential credential;
        String JsonCredentialsonFile = System.IO.File.ReadAllText(FullTokenAccessFileName);
        string credPath = basePath + @"\Credentials\token.json";
        // Force a Refresh of the Token
        RefreshTokenClass RTC = new RefreshTokenClass();
        // Set field values in RefreshTokenClass:
        var jObject = Newtonsoft.Json.Linq.JObject.Parse(JsonCredentialsonFile);
        var fieldStrings = jObject.GetValue("installed").ToString();
        var fields = Newtonsoft.Json.Linq.JObject.Parse(fieldStrings);
        RTC.client_id = fields.GetValue("client_id").ToString();
        RTC.client_secret = fields.GetValue("client_secret").ToString();
        RTC.refresh_token = fields.GetValue("refresh_token").ToString();
        RTC.ExecuteRefresh();  // this gets us a valid token every time

        try
        {
            GoogleCredential gCredentials = GoogleCredential.FromAccessToken(RTC.access_token);
            CurrentGDriveService = new DriveService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = gCredentials,
                ApplicationName = ApplicationName,
            });
            return true;
        }
        catch (Exception ex)
        {
            LastErrorMessage = "Error: Authenticating - " + ex.Message;
            return false;
        }
    }

Usage is pretty straight forward:

            string TokenFile = @basePath + @"\skeleton_key.json";
            GDRIVER.AuthenticateUser(TokenFile);
            var rslt = GDRIVER.LastErrorMessage;
            if (!String.IsNullOrEmpty(rslt))
            {
                WriteToLogFile("ERROR in Google AuthenticateUser() ");
                AlertMessage("Unable To Connect to Google Drive - Authorization Failed");
                return;
            }

And this is the class that refreshes the token via REST API as needed:

public class RefreshTokenClass
{
    public string application_name { get; set; }
    public string token_source { get; set; }
    public string client_id { get; set; }
    public string client_secret { get; set; }
    public string scope { get; set; }
    public string access_token { get; set; }
    public string refresh_token { get; set; }

    public RefreshTokenClass()
    {

    }

    public bool ExecuteRefresh()
    {
        try
        {
            RestClient restClient = new RestClient();
            RestRequest request = new RestRequest();
            request.AddQueryParameter("client_id", this.client_id);
            request.AddQueryParameter("client_secret", this.client_secret);
            request.AddQueryParameter("grant_type", "refresh_token");
            request.AddQueryParameter("refresh_token", this.refresh_token);
            restClient.BaseUrl = new System.Uri("https://oauth2.googleapis.com/token");
            var restResponse = restClient.Post(request);
            // Extracting output data from received response
            string response = restResponse.Content.ToLower();  // make sure case isn't an issue

            // Parsing JSON content into element-node JObject
            var jObject = Newtonsoft.Json.Linq.JObject.Parse(restResponse.Content);

            //Extracting Node element using Getvalue method
            string _access_token = jObject.GetValue("access_token").ToString();
            this.access_token = _access_token;
            return true;
        }
        catch (Exception ex)
        {
            //Console.WriteLine("Error on Token Refresh" + ex.Message);
            return false;
        }

    }

Note: This makes use of Newtonsoft.Json and RestSharp.

Thanks to user: "OL." who gave me the way of creating a service from a token (that somehow I missed in the docs!) How to create Service from Access Token

And to user:"purshotam sah" for a clean REST API approach Generate Access Token Using Refresh Token

MarkJoel60
  • 537
  • 2
  • 6
  • 24