admin管理员组

文章数量:1391868

I want to build an interface on my website (frontend) to enable clients to create events in my own Google Calendar (backend). I want to achieve this with the technologies JavaScript and/or PHP via Google Calendar API v3.

While working with this API is totally new for me I started with the code below which is a slightly modificated version of this mockup. It actually works like a charm but doesn't do what I need.

What I need is to authorize my particular site (lets say "axel/calendar" for example) to have "permanent" access to the events of my Google Calendar and to be able to add events based on particular actions of the user. The actual user of the interface doesn't have to authorize anything at all.

For the UI I tend to use FullCalendar by now.

<!DOCTYPE html>
<html>
  <head>
    <title>Google Calendar API Quickstart</title>
    <meta charset='utf-8' />
  </head>
  <body>
    <button id="authorize-button" style="display: none;">Authorize</button>
    <button id="signout-button" style="display: none;">Sign Out</button>
    <pre id="content"></pre>

    <script type="text/javascript">
      var CLIENT_ID = '<YOUR_CLIENT_ID>';
      var API_KEY = '<YOUR_API_KEY>';
      var DISCOVERY_DOCS = [""];
      var SCOPES = ".readonly";
      var authorizeButton = document.getElementById('authorize-button');
      var signoutButton = document.getElementById('signout-button');

      function handleClientLoad() {
        gapi.load('client:auth2', initClient);
      }

      function initClient() {
        gapi.client.init({
          apiKey: API_KEY,
          clientId: CLIENT_ID,
          discoveryDocs: DISCOVERY_DOCS,
          scope: SCOPES
        }).then(function () {
          gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
          updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
          authorizeButton.onclick = handleAuthClick;
          signoutButton.onclick = handleSignoutClick;
        });
      }

      function updateSigninStatus(isSignedIn) {
        if (isSignedIn) {
          authorizeButton.style.display = 'none';
          signoutButton.style.display = 'block';
          listUpingEvents();
        } else {
          authorizeButton.style.display = 'block';
          signoutButton.style.display = 'none';
        }
      }

      function handleAuthClick(event) {
        gapi.auth2.getAuthInstance().signIn();
      }

      function handleSignoutClick(event) {
        gapi.auth2.getAuthInstance().signOut();
      }

      function appendPre(message) {
        var pre = document.getElementById('content');
        var textContent = document.createTextNode(message + '\n');
        pre.appendChild(textContent);
      }

      function listUpingEvents() {
        gapi.client.calendar.events.list({
          'calendarId': 'primary',
          'timeMin': (new Date()).toISOString(),
          'showDeleted': false,
          'singleEvents': true,
          'maxResults': 10,
          'orderBy': 'startTime'
        }).then(function(response) {
          var events = response.result.items;
          appendPre('Uping events:');

          if (events.length > 0) {
            for (i = 0; i < events.length; i++) {
              var event = events[i];
              var when = event.start.dateTime;
              if (!when) {
                when = event.start.date;
              }
              appendPre(event.summary + ' (' + when + ')')
            }
          } else {
            appendPre('No uping events found.');
          }
        });
      }
    </script>

    <script async defer src=".js"
      onload="this.onload=function(){};handleClientLoad()"
      onreadystatechange="if (this.readyState === 'plete') this.onload()">
    </script>

I want to build an interface on my website (frontend) to enable clients to create events in my own Google Calendar (backend). I want to achieve this with the technologies JavaScript and/or PHP via Google Calendar API v3.

While working with this API is totally new for me I started with the code below which is a slightly modificated version of this mockup. It actually works like a charm but doesn't do what I need.

What I need is to authorize my particular site (lets say "axel./calendar" for example) to have "permanent" access to the events of my Google Calendar and to be able to add events based on particular actions of the user. The actual user of the interface doesn't have to authorize anything at all.

For the UI I tend to use FullCalendar by now.

<!DOCTYPE html>
<html>
  <head>
    <title>Google Calendar API Quickstart</title>
    <meta charset='utf-8' />
  </head>
  <body>
    <button id="authorize-button" style="display: none;">Authorize</button>
    <button id="signout-button" style="display: none;">Sign Out</button>
    <pre id="content"></pre>

    <script type="text/javascript">
      var CLIENT_ID = '<YOUR_CLIENT_ID>';
      var API_KEY = '<YOUR_API_KEY>';
      var DISCOVERY_DOCS = ["https://www.googleapis./discovery/v1/apis/calendar/v3/rest"];
      var SCOPES = "https://www.googleapis./auth/calendar.readonly";
      var authorizeButton = document.getElementById('authorize-button');
      var signoutButton = document.getElementById('signout-button');

      function handleClientLoad() {
        gapi.load('client:auth2', initClient);
      }

      function initClient() {
        gapi.client.init({
          apiKey: API_KEY,
          clientId: CLIENT_ID,
          discoveryDocs: DISCOVERY_DOCS,
          scope: SCOPES
        }).then(function () {
          gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
          updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
          authorizeButton.onclick = handleAuthClick;
          signoutButton.onclick = handleSignoutClick;
        });
      }

      function updateSigninStatus(isSignedIn) {
        if (isSignedIn) {
          authorizeButton.style.display = 'none';
          signoutButton.style.display = 'block';
          listUpingEvents();
        } else {
          authorizeButton.style.display = 'block';
          signoutButton.style.display = 'none';
        }
      }

      function handleAuthClick(event) {
        gapi.auth2.getAuthInstance().signIn();
      }

      function handleSignoutClick(event) {
        gapi.auth2.getAuthInstance().signOut();
      }

      function appendPre(message) {
        var pre = document.getElementById('content');
        var textContent = document.createTextNode(message + '\n');
        pre.appendChild(textContent);
      }

      function listUpingEvents() {
        gapi.client.calendar.events.list({
          'calendarId': 'primary',
          'timeMin': (new Date()).toISOString(),
          'showDeleted': false,
          'singleEvents': true,
          'maxResults': 10,
          'orderBy': 'startTime'
        }).then(function(response) {
          var events = response.result.items;
          appendPre('Uping events:');

          if (events.length > 0) {
            for (i = 0; i < events.length; i++) {
              var event = events[i];
              var when = event.start.dateTime;
              if (!when) {
                when = event.start.date;
              }
              appendPre(event.summary + ' (' + when + ')')
            }
          } else {
            appendPre('No uping events found.');
          }
        });
      }
    </script>

    <script async defer src="https://apis.google./js/api.js"
      onload="this.onload=function(){};handleClientLoad()"
      onreadystatechange="if (this.readyState === 'plete') this.onload()">
    </script>
Share Improve this question asked Nov 17, 2017 at 22:06 AxelAxel 3,32311 gold badges37 silver badges60 bronze badges 1
  • AFAIK, access token have limited lifetimes. If your application needs access to a Google API beyond the lifetime of a single access token, it can obtain a refresh token. A refresh token allows your application to obtain new access tokens. Check the documentation, about using OAuth 2.0 to Access Google APIs. Hope this helps. – Mr.Rebot Commented Nov 18, 2017 at 20:48
Add a ment  | 

2 Answers 2

Reset to default 7

Instead of using OAuth key you may use Service account credentials.

OAuth is used to access a client's calendar which requires the consent of the user.

Rather you should use Service account credentials to modify events in your own calendar which would be shared with the user.

On Google API developer console select the project and choose Service account for credentials instead of OAuth.

You will get a corresponding json credential file which you may use for authentication on Backend.

This link will help you out here (particularly if you are using PHP Laravell)

https://github./spatie/laravel-google-calendar

Documentation is lacking for JS/TS. Firstly install the googleApi.

npm install googleapis

As stated elsewhere you'll have to do this with a service account - make your service account (make sure you keep the json file that is provided) and add the Domain-wide Delegation. It will look something like this (... for omitted parts):

{
  "type": "service_account",
  "project_id": ...,
  "private_key_id": ...,
  "private_key": "-----BEGIN PRIVATE KEY-----/n ...",
  "client_email": "... @ ... aim.gserviceaccount.,
  "client_id": ...,
  "auth_uri": "https://accounts.google./o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis./token",
  "auth_provider_x509_cert_url": "https://www.googleapis./oauth2//v1/certs",
  "client_x509_cert_url": "https://www.googleapis./robot/v1/metadata/x509/ ...",
}

Typically, for backend applications which I find the main use case for skipping user auth, you'll have an auth manager. The following example assumes that you place the info from the downloaded json file in an external source:

 import {google, calendar_v3} from "googleapis";

 export class GoogleClient {
   private static instance: GoogleClient;
   private calendar: calendar_v3.Calendar;
   
   private constructor() {}
 
   static async getClient(): Promise<GoogleClient> {
     if (!GoogleClient.instance) {
       GoogleClient.instance = new GoogleClient();
       const config = <CONFIG FILE FETCH>
       const auth = new google.auth.GoogleAuth({
         scopes:["https://www.googleapis./auth/calendar.events.readonly"],
         credentials: {
           private_key: config.private_key.replace(/\\n/g, "\n"),
           client_email: config.client_email,
         },
         projectId: config.project_id,
       });
 
       GoogleClient.instance.calendar = google.calendar({
         version: "v3",
         auth,
       });
     }
 
     return GoogleClient.instance;
   }
 
   // Other methods here that use your instance
 }

The scopes above should match the scopes given on your Domain-wide Delegation. Some useful links to check your generated token (if you get an error you can go into the header to see your token):

www.googleapis./oauth2/v1/tokeninfo?access_token=<YOUR TOKEN>

an example of a method using the instance:

await this.calendar.events.list({
  calendarId: <SOME EMAIL>
}).then((calendar) => calendar.data.items.map((item) => item.summary);

If you have an authorized account on your domain you can use the google playground for most API calls to test different query parameters. Note that the AUTH in these will use redirect urls instead of the service account.

本文标签: javascriptHow to access my own Google Calendar permanently via Google Calendar API v3Stack Overflow