Link to home
Start Free TrialLog in
Avatar of AviationAce
AviationAceFlag for United States of America

asked on

Google Data Authentication in C# with 2-Step Verification

using System;
//using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;

using Google.GData.Client;
using Google.GData.Extensions;
using Google.GData.Calendar;
using System.Diagnostics;

namespace RepBusGoogleCalandar
{
    public class CalandarMain
    {

        public bool m_isInitialized;
        private CalendarService m_calServiceSDER;
        public gcEvent m_gcEvent;
        private EventQuery m_query;
        private EventFeed m_feed;
        public const char fs = (char)29;//13; //field separator

        public CalandarMain()
        {
            RefreshFeed();
        }

        ~CalandarMain()
        {
            
        }

        //OAuth 2.0

        private void RefreshFeed()
        {
            bool bolGood;

            m_calServiceSDER = new CalendarService("SDERcalApp");
            m_calServiceSDER.setUserCredentials("MyUN", "MyPW");   // <----- UN and PW hard coded here

            //InvalidCredentialsException
            m_query = new EventQuery();
            m_query.Uri = new Uri(calendarURI);
            m_query.NumberToRetrieve = int.MaxValue;
            bolGood = false;
            try
            {
                m_feed = m_calServiceSDER.Query(m_query) as EventFeed;
                bolGood = true;
            }
            catch (Exception e)
            {
                string cs_err;
                cs_err = e.Message;
                Console.WriteLine(cs_err);
                Console.WriteLine(e.Source);
                //MessageBox.Show(cs_err, e.Source);
            }
            m_gcEvent = new gcEvent();
            if(bolGood)
            {
                Console.WriteLine("****** RefreshFeed: calFeed.Entries.Count: " + m_feed.Entries.Count);
            }
            m_isInitialized = bolGood;
        }
}

Open in new window


This code listed here worked just fine until I set up Google 2-Step Verification.
https://www.google.com/landing/2step/

Question: What extra code is needed to deal with the Google 2-Step Verification process?
NOTE: Look were I have the //InvalidCredentialsException notation.

Thanks!
 - Dave
Avatar of David Johnson, CD
David Johnson, CD
Flag of Canada image

use an application password https://www.google.com/settings/security
Avatar of AviationAce

ASKER

I understand that in concept, but need help in hammering out the details.  If you were going to modify the class I posted, where exactly would you start?

Please note: I have already created a new "Client ID for native application" at the Google Developers Console.  See the attachment.
Screenshot-2014-09-20-08.07.59.png
It appears to me that modifying the old class is not feasible.  So, I am writing a new one using the new V3 interface.

I'm getting a type conversion error and I don't understand why.  Please look at the comment that starts with Error 1 and advise.

using System;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Diagnostics;

//For use in class CalandarMain
//using Google.GData.Client;
//using Google.GData.Extensions;
//using Google.GData.Calendar;


//For use in class CalandarMainV3  :  An entirly new class needed to 
using System.Threading;
using System.Threading.Tasks;
using Google;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;

    public class CalandarMainV3
    {
        const String ClientSecretsFile = "C:\\Users\\User1\\Documents\\Visual Studio 2010\\Projects\\Programming\\Projects\\Google Ops\\client_secrets.json";

        const String CalAppName = "MyCalAppV3";

        bool m_Init;

        public CalandarMainV3()
        {
            m_Init = AuthGoogleDataInterface();
        }

        private bool AuthGoogleDataInterface()
        {
            bool b_success;
            try
            {
                UserCredential credential;

                using (var stream = new FileStream(ClientSecretsFile, FileMode.Open, FileAccess.Read))
            {
                //Error	1	Cannot implicitly convert type 'System.Threading.Tasks.Task<Google.Apis.Auth.OAuth2.UserCredential>' to 'Google.Apis.Auth.OAuth2.UserCredential'	C:\Users\user1\Documents\Visual Studio 2010\Projects\Programming\Projects\Google Ops\RepBusGoogleCalandar\RepBusGoogleCalandar\ClalandarMain.cs	273	30	RepBusGoogleCalandar
                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    new[] { Google.Apis.Calendar.v3.CalendarService.Scope.Calendar },
                    "user",
                    CancellationToken.None,
                    new FileDataStore("Calendar.MyCal")
                    );
            }
                Console.WriteLine("AuthGoogleDataInterface: Success");
                b_success = true;
            }
            catch (Exception e)
            {
                string cs_err;
                cs_err = e.Message;
                Console.WriteLine(cs_err);
                Console.WriteLine(e.Source);
                Console.WriteLine("AuthGoogleDataInterface: Fail");
                b_success = false;
                throw;
            }

            return b_success;
        }
    }
}

Open in new window

The code below complies correctly and runs, but I am now having a problem with the CLIENT SECRETS file.

using System;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Diagnostics;

//For use in class CalandarMainV3  :  An entirely new class needed to 
using System.Threading;
using System.Threading.Tasks;
using Google;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;

namespace RepBusGoogleCalendarV3
{
    public class CalandarMainV3
    {
        const String ClientSecretsFile = "C:\\Users\\user1\\Documents\\Visual Studio 2010\\Projects\\Programming\\Projects\\Google Ops\\client_secrets.json";

        bool m_Init;

        public CalandarMainV3()
        {
            Console.WriteLine("Calling: AuthGoogleDataInterface()");
            m_Init = AuthGoogleDataInterface();
        }

        private bool AuthGoogleDataInterface()
        {
            bool b_success;
            try
            {
                Console.WriteLine("New User Credential");
                // New User Credential
                UserCredential credential;
                using (var stream = new FileStream(ClientSecretsFile, FileMode.Open, FileAccess.Read))
                {
                    credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                        GoogleClientSecrets.Load(stream).Secrets,
                        new[] { CalendarService.Scope.Calendar },
                        "user", CancellationToken.None,
                        null).Result;
                        //new FileDataStore("My.cal")).Result;
                }

                Console.WriteLine("New Service");
                // Create the service.
                var service = new CalendarService(new BaseClientService.Initializer
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "My Calendar API",
                });
                
                Console.WriteLine("AuthGoogleDataInterface: Success");
                b_success = true;
            }
            catch (Exception e)
            {
                string cs_err;
                cs_err = e.Message;
                Console.WriteLine(cs_err);
                Console.WriteLine(e.Source);
                Console.WriteLine("AuthGoogleDataInterface: Fail");
                b_success = false;
                throw;
            }
            return b_success;
        }
    }
}

Open in new window


Contents of the client_secrets.json file.

{"installed":{"auth_uri":"https://accounts.google.com/o/oauth2/auth","client_secret":"xxxxxxxxxxxxxxxxxxxxxxxx","token_uri":"https://accounts.google.com/o/oauth2/token","client_email":"","redirect_uris":["urn:ietf:wg:oauth:2.0:xxx","xxx"],"client_x509_cert_url":"","client_id":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs"}}

Open in new window


When I run the program, it loads a web page with the following contents:

401. That’s an error.

Error: invalid_client

no application name

Request Details
scope=https://www.googleapis.com/auth/calendar
response_type=code
redirect_uri=http://localhost:00000/authorize/
access_type=offline
client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com

That’s all we know.

What am I doing wrong?
ASKER CERTIFIED SOLUTION
Avatar of AviationAce
AviationAce
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
That fact that a project name hadn't been set up yet was key.  That should be documented better.