Solved

Google Data Authentication in C# with 2-Step Verification

Posted on 2014-09-19
6
1,706 Views
Last Modified: 2015-03-02
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
0
Comment
Question by:AviationAce
  • 5
6 Comments
 
LVL 78

Expert Comment

by:David Johnson, CD, MVP
ID: 40334019
use an application password https://www.google.com/settings/security
0
 

Author Comment

by:AviationAce
ID: 40334351
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
0
 

Author Comment

by:AviationAce
ID: 40339255
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

0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 

Author Comment

by:AviationAce
ID: 40347101
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?
0
 

Accepted Solution

by:
AviationAce earned 0 total points
ID: 40347667
stackoverflow.com/questions/18677244/error-invalid-client-no-application-name

At the link above I discovered that the error was being caused because I had not set up "Project Name" in my Google APIs Dashboard.

After setting it up the code ran with out error.  The first time I ran it a web page was displayed asking me to ok this device to use the service.
0
 

Author Closing Comment

by:AviationAce
ID: 40361055
That fact that a project name hadn't been set up yet was key.  That should be documented better.
0

Featured Post

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
This Micro Tutorial will demonstrate the easy use of Gmail embedding images in your email so the recipient of your email can view them in context.
Shows how to create a shortcut to site-search Experts Exchange using Google in the Chrome browser. This eliminates the need to type out site:experts-exchange.com whenever you want to search the site. Launch the Search Engine Menu: In chrome, via you…

930 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now