Viewed   100 times

I am writing a PHP application that's supposed to allow users to add certain events to a private Google Calendar. The calendar is owned by me, and I need a way for PHP to communicate with the calendar API using fixed credentials (everyone can add events using a form on the website, but the calendar itself is not publicly visible).

From what I have read, this is possible using ClientLogin in the v1 API. In the v3 API, however, the available options are OAuth2.0 or the API key. Using the API key doesn't seem to work, since it can only be used for requests that don't require authorization, and OAuth doesn't seem right either, because users are not supposed to access their own calendars, but the one my application uses.

I thought about getting the OAuth token programatically, but that's bound to break sooner or later, since the OAuth dialog can use captchas.

This seems to be such a standard use case — a web application that lets users interact with a single calendar in some predefined ways — yet I can't find any documentation on how to make it happen in the v3 API. Can anyone help me?

 Answers

2

You will need to use both the Developer Key (API Key) and OAuth2. The developer key authenticates who wrote the software and is used for things like quota which is on a per developer basis not a per user basis. OAuth2 is for user authentication and will be need to access the non-public calendar.

OAuth2 has a renew token from which you can generate a session token and this means that you will not need to screen scrape the OAuth screens to get authenticated. To get this I would write a little command line application, or you use a one off PHP page.

  1. Under the Google Api Console go to API Access
  2. Generate a new Client ID and choose Installed Application ( as you will be authenticating you server as you not as your user)
  3. Either using a console app or a one off PHP page authenticate using OAuth and your google account (the one with the calendar you want access to)
  4. In the return from the authentication there should be a renew token, (called renew or refresh or something similar). Save this string and make it available to your PHP site.
  5. When you need to access the service your OAuth library should have a renew/refresh call. There is an example using .Net below.

private IAuthorizationState CreateAuthorization(NativeApplicationClient arg)
 {
   // Get the auth URL:
   IAuthorizationState state = new AuthorizationState(new[] { AdsenseService.Scopes.AdsenseReadonly.GetStringValue() });
   state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
   if (refreshToken.IsNotNullOrEmpty()) // refreshToken you stored in step 4
   {
     try
     {
       state.RefreshToken = refreshToken;
       if (arg.RefreshToken(state))     // This is calling out to the OAuth servers with the refresh token getting back a session token, returns true if successful.
       {
         if (state.RefreshToken != refreshToken) // if the refresh token has changed, save it.
         {
           PersistRefreshToken(authorization.RefreshToken);
         }
         return this.authorization = state; // Retain the authorization state, this is what will authenticate your calls.
       }
     }
     catch (ProtocolException ex) {...}

The AuthorisationState that has now been renewed can then be used to authenticate call you make to the API. this state can be used many time until it expires and then can be refreshed. As you are authenticating your application as yourself not as a user this AuthorisationState can be shared by all you sessions. Both the current AuthorisationState and the refresh token should be kept securely on your server and never sent to the client, if you ever sent these as part of a response your clients would have the same privileges as your code application

Monday, November 14, 2022
5

It seems the mistake is because you send a DELETE http verb instead of a POST. Also, the XML namespace attributes in the entry are not required.

By the way, maybe this is a typo, you wrote 'content-lenght' instead of content-length.

Don't send any content in the entry for deletions, as it's not required (and not documented).

$xmlBuild = "<feed xmlns='http://www.w3.org/2005/Atom'
    xmlns:batch='http://schemas.google.com/gdata/batch'
    xmlns:gd='http://schemas.google.com/g/2005'
    xmlns:gContact='http://schemas.google.com/contact/2008'>";
$xmlBuild .= "<entry>";
$xmlBuild .= "<batch:id>1</batch:id><batch:operation type='delete'/>";
$xmlBuild .= "<id>http://www.google.com/m8/feeds/contacts/my.domain/base/1b93ef80b806243</id>";
$xmlBuild .= "</entry>";
$xmlBuild .= "</feed>";

$len = strlen($xmlBuild);
$options = array(
    "headers" => array(
        "Content-type" => "application/atom+xml; charset=UTF-8;",
        "Content-length" => $len
    ),
    "body" => $xmlBuild
);

$httpClient = $client->authorize();
$request = $httpClient->post("https://www.google.com/m8/feeds/contacts/my.domain/full/batch", $options); 
// or $request = $httpClient->sendRequest('POST', "https://www.google.com/m8/feeds/contacts/my.domain/full/batch", $options); 

$response = $request->getBody()->getContents();

print_r($response);
Saturday, October 8, 2022
 
1

First check the settings in the developer console of Google to see if your RedirectUri is the same and that the API is activated (although if you already got that .json, then I assume it is.

You have to go through the Google Auth Prompt Screen at least 1 time to get a refresh token in your .json, and if your RedirectUri is taking you nowhere, you won't be able to get your refresh token or even the access validated.

You can also try a service account if you're doing small file transactions and don't need a user validation for the process of your script. Good Luck.

Monday, December 26, 2022
 
5

There is definitely something wrong with your authentication. Here is a copy of my Service account authentication method.

 /// <summary>
        /// Authenticating to Google using a Service account
        /// Documentation: https://developers.google.com/accounts/docs/OAuth2#serviceaccount
        /// </summary>
        /// <param name="serviceAccountEmail">From Google Developer console https://console.developers.google.com</param>
        /// <param name="keyFilePath">Location of the Service account key file downloaded from Google Developer console https://console.developers.google.com</param>
        /// <returns></returns>
        public static CalendarService AuthenticateServiceAccount(string serviceAccountEmail, string keyFilePath)
        {

            // check the file exists
            if (!File.Exists(keyFilePath))
            {
                Console.WriteLine("An Error occurred - Key file does not exist");
                return null;
            }

            string[] scopes = new string[] {
        CalendarService.Scope.Calendar  ,  // Manage your calendars
        CalendarService.Scope.CalendarReadonly    // View your Calendars
            };

            var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
            try
            {
                ServiceAccountCredential credential = new ServiceAccountCredential(
                    new ServiceAccountCredential.Initializer(serviceAccountEmail)
                    {
                        Scopes = scopes
                    }.FromCertificate(certificate));

                // Create the service.
                CalendarService service = new CalendarService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Calendar API Sample",
                });
                return service;
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.InnerException);
                return null;

            }
        }

I have a tutorial on it as well. My tutorial Google Calendar API Authentication with C# The code above was ripped directly from my sample project Google-Dotnet-Samples project on GitHub

Note/headsup: Remember that a service account isn't you. It does now have any calendars when you start you need to create a calendar and insert it into the calendar list before you are going to get any results back. Also you wont be able to see this calendar though the web version of Google Calendar because you cant log in as a service account. Best work around for this is to have the service account grant you permissions to the calendar.

Wednesday, October 26, 2022
 
5

I don't know about using it in Delphi but there is a client API library for java, python... I've already used the java one and it's clearly explained how to use it in the documentation.

Google Calendar API 3 Doc page: https://developers.google.com/google-apps/calendar/

However, the service asks you to be authentified to used it (which is your problem if I understand it well, you don't want the user to have to authenticate). So I suggest you to have a look on OAuth2.0. https://developers.google.com/google-apps/calendar/auth

Here are some simple of using google-api-java-client for exemple : https://code.google.com/p/google-api-java-client/wiki/OAuth2

And you should look more precisely at Google OAuth service account possibilities. Service Account with OAuth2.0. (See here : https://developers.google.com/accounts/docs/OAuth2#serviceaccount). It will provide a service account for your application, from which you will be able to handle calendars for your app.

And here you will find a sample showing how to do it with Java. (https://code.google.com/p/google-api-java-client/wiki/OAuth2#Service_Accounts). But maybe this is the public API Key you are talking about... Not sure I remember properly.

I hope this will help you to figure out how to do it.

Friday, September 2, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :