13

I've been looking at the Oauth .Net Google Apis in order to authenticate via OAuth and use the Google drive Apis.

Specifically, I want to use a refresh token I already have stored in order to use it to instantiate a GoogleDrive service.

I've found samples like https://code.google.com/p/google-api-dotnet-client/source/browse/Tasks.SimpleOAuth2/Program.cs?repo=samples

That seem to use "GoogleWebAuthorizationBroker.AuthorizeAsync" but I'm not sure how I can use that method with a refresh token rather than the client secrets you seem to be feeding it in this example.

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
Dan G
  • 836
  • 11
  • 31
  • A couple of comments. OAuth is for authorization, not authentication (although it kinda authenticates as a by-product). When you say "existing refresh token", be sure that the refresh token was generated with the appropriate drive scope(s). Since you already have a refresh token, you have no need to authorize again, so you will *not* be using GoogleWebAuthorizationBroker. I don't know .NET enough to answer your question fully, but from the answers already posted, the one from peleyal is the closest. – pinoyyid Jan 09 '14 at 10:21
  • Thanks all. You've given me alot of good leads to follow up on. – Dan G Jan 09 '14 at 13:55

4 Answers4

23

If I understand you correctly, you are asking how can you create a new Google service, based on an existing refresh token.

So, you can do the following:

var token = new TokenResponse { RefreshToken = "YOUR_REFRESH_TOKEN_HERE" }; 
var credentials = new UserCredential(new GoogleAuthorizationCodeFlow(
    new GoogleAuthorizationCodeFlow.Initializer 
    {
      ClientSecrets = [your_client_secrets_here]
    }), "user", token);

Then you can pass your credentials to the service's initializer.

By doing the above, GoogleAuthorizationCodeFlow will get a new access token based on you refresh token and client secrets.

Note that you must have client secrets here, without that, you won't be able to get an access token.

peleyal
  • 3,472
  • 1
  • 14
  • 25
  • This does seem the closes to what I want. I'll follow up on this. And I do have client secrets for my app set up. Thanks. – Dan G Jan 09 '14 at 14:20
  • 1
    Exactly what I needed and working correctly in my code.Thanks very much. – Dan G Jan 10 '14 at 19:20
  • For others who end up here, the method above replaces the "IAuthenticator" technique in previous versions which is still features in the documentation, example apps, and SO answers. – Josh Fischer Aug 05 '14 at 02:43
  • @peleyal This doesn't seem to be working for me.. do you have a full working example for it somewhere? – supersan Jul 22 '15 at 07:06
  • I'm sorry to hear, it did work for others, so I recommend you to open a new thread with your code, and explain what doesn't work with link to this issue. Makes sense? – peleyal Jul 23 '15 at 01:45
  • 2
    How do you obtain "YOUR_REFRESH_TOKEN_HERE"? – PRMan Nov 20 '18 at 22:56
  • 1
    How do you obtain the REFRESH TOKEN from the existing file data store object? – Andrew Truckle Jun 13 '19 at 04:44
2

To use refresh token:

var init = new GoogleAuthorizationCodeFlow.Initializer
{
    ClientSecrets = new ClientSecrets
    {
        ClientId = "OAuth_Client_ID_From_GoogleAPI",
        ClientSecret = "OAuth_Client_Secret"
    },
    Scopes = new string[] {"MY_SCOPES"}
};
var token = new TokenResponse { RefreshToken = "MY_REFRESH_TOKEN" };
var credential = new UserCredential(new Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow(init), "", token);

//init your Google API service, in this example Google Directory
var service = new DirectoryService(new BaseClientService.Initializer()
{
    HttpClientInitializer = credential,
    ApplicationName = "",
});

What if you don't have a refresh token? The easiest is to follow the instructions on Google SDK docs. First download your credentials from Google API project. Name the file credentials.json. Then run the code:

using (var stream =
    new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
{
    // The file token.json stores the user's access and refresh tokens, and is created
    // automatically when the authorization flow completes for the first time.
    string credPath = "token.json";
    credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
        GoogleClientSecrets.Load(stream).Secrets,
        Scopes,
        "user",
        CancellationToken.None,
        new FileDataStore(credPath, true)).Result;
    Console.WriteLine("Credential file saved to: " + credPath);
}

This should create a folder token.json and inside folder is another json file that has your refresh_token.

{
    "access_token" : "asdf",
    "token_type" : "Bearer",
    "expires_in" : 3600,
    "refresh_token" : "XXX",
    "scope" : "https://www.googleapis.com/auth/admin.directory.user.readonly",
    "Issued" : "2019-02-08T12:37:06.157-08:00",
    "IssuedUtc" : "2019-02-08T20:37:06.157Z"
}

I prefer not to use the GoogleWebAuthorizationBroker because it auto launches a web browser when the token is not found. I prefer the old school way of getting the refresh token by access code. This is very similiar to the using the Google OAuthUtil.CreateOAuth2AuthorizationUrl and OAuthUtil.GetAccessToken in Google's legacy OAuth API.

var a = new Google.Apis.Auth.OAuth2.Flows.GoogleAuthorizationCodeFlow.Initializer
{
    ClientSecrets = new ClientSecrets
    {
        ClientId = "asdf",
        ClientSecret = "hij"
    },
    Scopes = Scopes
};
var flow = new Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow(a);
var url = flow.CreateAuthorizationCodeRequest(GoogleAuthConsts.InstalledAppRedirectUri).Build().AbsoluteUri;
Console.WriteLine("Go to this URL and get access code: " + url);

Console.Write("Enter access code: ");
var code = Console.ReadLine();

Console.WriteLine("Fetching token for code: _" + code + "_");
var r = flow.ExchangeCodeForTokenAsync("user", code, GoogleAuthConsts.InstalledAppRedirectUri, CancellationToken.None).Result;
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(r));
  • Important note to make! To make it not launch a web browser, you can parse in the parameter of new PromptCodeReceiver() inside GoogleWebAuthorizationBroker.AuthorizeAsync() after your new FileDataStore()! This will, essentially, do the same as the fourth section of code you showed, prompting the user instead of opening the browser. Cool stuff though! – FeroxFoxxo Oct 27 '21 at 14:07
0

The client_secrets.json contains the client ID and client secret (which has your OAuth 2.0 information for your application).

I think this article will explain better how you can OAuth 2.0 to access Google Apps APIs especially if you are building a web application.

https://developers.google.com/accounts/docs/OAuth2WebServer

If you are interested in an coding example, there is one in stackoverflow: Google+ API: How can I use RefreshTokens to avoid requesting access every time my app launches?

Community
  • 1
  • 1
Emily
  • 1,464
  • 1
  • 9
  • 12
  • Thanks Emily. I did see and use that code sample in the past and it did work. But it seems to be the old obsoleted method to use OAuth using "NativeApplicationClient". I guess the new stuff has all new structures to use. Thanks again! – Dan G Jan 09 '14 at 14:01
0

GoogleWebAuthorizationBroker requires that you send it an implimtation of iDataStore in this case FileDatastore is sent. FileDataStore stores the data in %appData%. If you want to use a refreshtoken you saved someplace else you need to create your own implimitation of iDataStore.

The code for the actual datastore i a little long to post here. http://daimto.com/google-oauth2-csharp/

You then use it just like you would the FileDataStore

//Now we load our saved refreshToken.
StoredResponse myStoredResponse = new StoredResponse(tbRefreshToken.Text);
// Now we pass a SavedDatastore with our StoredResponse.
 using (var stream = new FileStream("client_secrets.json", FileMode.Open,
        FileAccess.Read))
  {
     GoogleWebAuthorizationBroker.Folder = "Tasks.Auth.Store";
     StoredCredential = GoogleWebAuthorizationBroker.AuthorizeAsync(
     GoogleClientSecrets.Load(stream).Secrets,
     new[] { DriveService.Scope.Drive,
     DriveService.Scope.DriveFile },
     "user",
      CancellationToken.None,
      new SavedDataStore(myStoredResponse)).Result;
     }

There is a sample project attached to that tutorial.

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • I saw that filedatastore and figured it might contain a refresh token, I just couldn't find any info on it. Thanks for the link – Dan G Jan 09 '14 at 13:57