karlwancl / GoogleCloudPrintApi

A .NET wrapper for Google Cloud Print API, based on .NET standard 1.4
MIT License
12 stars 14 forks source link

Cannot get authorization code #20

Closed awerber closed 7 years ago

awerber commented 7 years ago

Hi, I sent you an email about this a while ago. Since then, I've tried to do a workaround of this problem, but I'm still stuck at getting the token. So, I recently tried to go back and try your code again.

I noticed that in your sample code for getting a token:

var provider = new GoogleCloudPrintOAuth2Provider(clientId, clientSecret);

// You should have your redirect uri here if your app is a server application, o.w. leaving blank is ok var url = provider.BuildAuthorizationUrl(redirectUri);

/ Your method to retrieve authorization code from the above url / var token = await provider.GenerateRefreshTokenAsync(authorizationCode, redirectUri);

You indicate that a method has to be supplied to get the authorization code from the URL returned by provider.BuildAuthorizationUrl. Can you give an example of such a method?

In my attempt to work around this issue, I have been using code at https://developers.google.com/identity/sign-in/web/server-side-flow. It seems to me that the JavaScript function returns an authorization code. For example, I get something like 4/bGoyOzdR57onTpPmabFRpKmJQFQngalri-sUvdqhxDU. Is this the kind of string you get from using the url returned by provider.BuildAuthorizationUrl?

karlwancl commented 7 years ago

@awerber yes, it's the authorization code. If you paste the url generated from BuildAuthorizationUri to browser & authorize, the code will also be displayed on the returned uri (e.g. http://localhost:5000?code=4/bGoyOzdR57onTpPmabFRpKmJQFQngalri-sUvdqhxDU)

awerber commented 7 years ago

Karl,

Thank you for your prompt response.

First, I’ve never seen a response like you showed below.

Here’s some code I have that looks like your example code:

public GCPOauth2Services(string clientId, string clientSecret) { Provider = new GoogleCloudPrintOAuth2Provider(clientId, clientSecret);

        // lines below like code from IPKarl, https://github.com/lppkarl/GoogleCloudPrintApi, where he has code that
        string redirectURL = ConfigurationManager.AppSettings["redirectURLForTokens"];
        string authURL = Provider.BuildAuthorizationUrl(redirectURL);
        var process = Process.Start(authURL);
    }

This is a constructor that wraps your code.

The input variables, clientId and clientSecret are provided from a Web config file. I have confirmed that. The vales come from the https://console.developers.google.com/apis/credentials/oauthclient/ page for the OAuth2 credentials for my Gmail account that controls the printers. The client ID ends with apps.googleusercontent.com. The client secret is about 25 characters long. My test URL is listed under the Authorized JavaScript origins listing. So, I’m very confident that Provider object is correctly instantiated.

The redirectURL is listed in the Authorized redirect URIs in the page as the Authorized JavaScript origins.

The URL I get from the BuildAuthorizationUrl (I replaced the client ID with the letter x) is: https://accounts.google.com/o/oauth2/auth?redirect_uri=http%3A%2F%2Flocalhost%3A8080%2F&response_type=code&client_id=xxxxxxxxxxxxxxxxxx.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloudprint%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgoogletalk%20email&approval_prompt=force&access_type=offline

The response from the page when I call Process.Start is (I replace client Id again):

  1. That’s an error.

Error: invalid_client

The OAuth client was not found.

Request Details redirect_uri=http://localhost:8080/ response_type=code client_id=xxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com scope=https://www.googleapis.com/auth/cloudprint https://www.googleapis.com/auth/googletalk email approval_prompt=force access_type=offline That’s all we know.

So, I would like to know what I’m doing wrong, because I never see a URI response with the authorization code like you get. Maybe something is wrong with my configuration of the OAuth2 credential?

However, as you saw I was able to get the authorization code, but using code I found at https://developers.google.com/identity/sign-in/web/server-side-flow. I added the JavaScript as per the code. I found that if I put an alert(authResult['code']) in the code listed under Step 6, I see an authorization code. I then created a REST web service where I do a post and pass the authorization code to your code to try to get the token. Here’s this code: private string getToken (string authCode) { string refreshTokenSTR = string.Empty; // the web.config used is NOT inherited from the calling web site string clientId = ConfigurationManager.AppSettings["clientId"]; string clientSecret = ConfigurationManager.AppSettings["clientSecret"];

        GoogleCloudPrintOAuth2Functions.GCPOauth2Services authService = new GCPOauth2Services( clientId, clientSecret);
        try
        {
            GoogleCloudPrintApi.Models.Token refreshToken = authService.GetToken(authService.Provider, authCode);
            refreshTokenSTR = refreshToken.ToString();
        }
        catch (Exception ex)
        {
            string msg = ex.Message;
            if (ex.InnerException != null)
            {
                string InnerMsg = ex.InnerException.Message;
            }
        }

        return refreshTokenSTR;

    }

Here’s the code for my GetToken method: public Token GetToken(GoogleCloudPrintOAuth2Provider provider, string authCode) { string redirectURL = ConfigurationManager.AppSettings["redirectURLForTokens"]; var t = provider.GenerateRefreshTokenAsync(authCode, redirectURL).Result; return t;

    }

Again, I’ve confirmed provider, authCode and redirectURL all look good.

I’ve confirmed, using the debugger, that the values for clientId, clientSecret and authCode. The GetToken is a wrapper around your code that ultimately calls the GenerateRefreshTokenAsync. Whenever I call this method, I get the following exception right after the call to GenerateRefreshTokenAsync:

Request to https://accounts.google.com/o/oauth2/token failed with status code 401 (Unauthorized).

Given that I keep getting this 401 (Unauthorized) error when trying to get the authorization code in the first example, and again when trying to get the token in the second example, my guess is that there’s something wrong with the way my Gmail account is configured.

I would appreciate any insight you have that might help me.

Regards,

Andrew Werber

From: Karl Wan [mailto:notifications@github.com] Sent: Tuesday, October 10, 2017 10:18 PM To: lppkarl/GoogleCloudPrintApi GoogleCloudPrintApi@noreply.github.com Cc: Andrew Werber Andrew_Werber@tritonmsllc.com; Mention mention@noreply.github.com Subject: Re: [lppkarl/GoogleCloudPrintApi] Cannot get authorization code (#20)

@awerberhttps://github.com/awerber yes, it's the authorization code. If you paste the url generated from BuildAuthorizationUri to browser & authorize, the code will also be displayed on the returned uri (e.g. http://localhost:5000?code=4/bGoyOzdR57onTpPmabFRpKmJQFQngalri-sUvdqhxDU)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/lppkarl/GoogleCloudPrintApi/issues/20#issuecomment-335685747, or mute the threadhttps://github.com/notifications/unsubscribe-auth/Ae0PMZmqWQke2vVw7hHRzIr2DnLlQOtvks5srE9vgaJpZM4P0qQx.

This email has been scanned for email related threats and delivered safely by Mimecast. For more information please visit http://www.mimecast.com

karlwancl commented 7 years ago

@awerber in https://developers.google.com/identity/sign-in/web/server-side-flow, you may have to select "Other" in application type instead of web application for server type application. See if it works.

awerber commented 7 years ago

Thank you for the suggestion.

I set up another OAuth2 client ID with type 'other' and replaced the client ID for the Web type with the client ID of the other type. When I ran the page containing the code from the server-side-flow page, I got a JavaScript error at auth2.grantOfflineAccess().then(signInCallback);

I have a question, have you ever added a new printer to your account with the /register interface?

karlwancl commented 7 years ago

@awerber This wrapper is originally created when i was working on a project for google cloud print integration. Most of them including /register interface were used in the project, it should function correctly if everything is well-configured.

The project's server-side was C#-based, the client-side was js-based. But all the operation related to Google cloud print communication was done in C# part from authroization/ get tokens/ register/ accept upload, etc.

It is wise you use this library entirely in c#, as i did not test the use-case with js. And don't know if it works for token generated from js, although it should behave the same if both c#/js shares the same configuration in Google Cloud Developer Console.

awerber commented 7 years ago

Karl, thank you for your reply. You were 100% correct in your guidance. I was able to use your code to get the authorization code after setting up an 'Other' type of project, just like you described.