Google API OAuth2,服务帐户,“错误” :“invalid_grant” [英] Google API OAuth2, Service Account, "error" : "invalid_grant"

查看:299
本文介绍了Google API OAuth2,服务帐户,“错误” :“invalid_grant”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用服务帐户将日历从Dynamics CRM软件同步到Google。
在此期间,我面临.net的API的文档缺乏,特别是有关授权。由于过时的库和类的使用,大部分Google样本都无法编译。

所以我发现了一些关于interned和receive错误的例子。 有人可以看看我的样本,并告诉我做错了什么?



准备步骤:


  1. 我在我的私人Google帐户中创建了一个项目。

  2. 在项目开发者控制台中,在APIS& AUTH - >凭证,我生成了服务帐户。然后点击Generate P12 key并下载.p12文件。

  3. 在APIS& AUTH - > API,打开Calendar API


$ b 然后创建控制台应用程序,并设法安装OAuth和Calendar nuget包。有:


  1. Google API Auth客户端库,Google.Apis.Auth 1.8.1

  2. Google API客户端库,Google.Apis 1.8.1

  3. Google API核心客户端库,Id:Google.Apis.Core 1.8.1

  4. Google .APIs.Calendar.v3客户端库,Google.Apis.Calendar.V3 1.8.1.860

找到并修改了代码我的需求:
$ b

  using System; 
使用System.Security.Cryptography.X509Certificates;
使用Google.Apis.Calendar.v3;
使用Google.Apis.Auth.OAuth2;
使用Google.Apis.Services;

namespace CrmToGoogleCalendar
{
class Program
{

static void Connect()
{
var certificate = new X509Certificate2(My Project-ee7facaa2bb1.p12,notasecret,X509KeyStorageFlags.Exportable);


var serviceAccountEmail =506310960175-q2k8hjl141bml57ikufinsh6n8qiu93b@developer.gserviceaccount.com;
var userAccountEmail =<我的电子邮件> @ gmail.com;
var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User = userAccountEmail,
Scopes = new [] {CalendarService.Scope.Calendar}
}
.FromCertificate(certificate));

var service = new CalendarService(新BaseClientService.Initializer()
{
ApplicationName =测试日历同步应用程序,
HttpClientInitializer =凭证

});

var calList = service.CalendarList.List()。Execute()。Items;


foreach(calList中的var cal)
{
Console.WriteLine(cal.Id);



$ b $ static void Main(string [] args)
{
Connect();


$ b $ / code $ / pre
$ b $ p与Google API的沟通我在应用程序和Fiddler中看到:
$ b

请求:


主持人: HTTPS accounts.google.com,URL:/ o / oauth2 / token

断言:long二进制字符串

grant_type:urn:ietf:params:oauth:grant-type:jwt- bearer

响应:
$ b


HTTP / 1.1 400错误请求Content-Type:application / json Cache-Control:
no-cache,no-store,max-age = 0,必须重新验证Pragma:no-cache
过期时间:星期五,01 Jan 1990 00:00:00 GMT日期:2014年7月24日星期四06:12:18
GMT X-Content-Type-Options:nosniff X-Frame-Options:SAMEORIGIN
X-XSS-Protection :1; mode = block Server:GSE Alternate-Protocol:
443:quic Transfer-Encoding:chunked

1f {error:invalid_grant} 0




请帮助并提前致谢!

解决方案

发现,Google API无法按照您的个人帐户@ gmail.com的预期工作。您应该在Google中拥有组织域帐户,格式为you @ your_organisation_domain



然后,还有一些令人困惑的事情,那就是 Google Drive API页面 委托您的服务帐户授予域名权限 日历API页面中未提及的部分。
该部分有7个步骤,需要完成。


个人帐户管理网站admin.google.com的BTW甚至无法使用。因此,使用@ gmail.com帐户执行这7个步骤是不可能的。 然后,当客户端通过 Google Apps管理控制台>安全>高级设置>管理OAuth客户端访问进行授权时,代码开始工作。



有一个代码适用于我:

 使用System; 
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用System.Security.Cryptography.X509Certificates;
使用Google.Apis.Calendar.v3;
使用Google.Apis.Calendar.v3.Data;
使用Google.Apis.Auth.OAuth2;
使用Google.Apis.Services;

namespace CrmToGoogleCalendar
{
class Program
{

static void Connect()
{
Console。 WriteLine(通过OAuth2服务帐户示例的日历);

var certificate = new X509Certificate2(My MC Project-3f38defdf4e4.p12,notasecret,X509KeyStorageFlags.Exportable);
var serviceAccountEmail =795039984093-c6ab1mknpediih2eo9cb70mc9jpu9h03@developer.gserviceaccount.com;
var userAccountEmail =me@testdomain.com;
var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User = userAccountEmail,
Scopes = new [] {CalendarService.Scope.Calendar}
}
.FromCertificate(certificate));

var service = new CalendarService(新BaseClientService.Initializer()
{
ApplicationName =测试日历同步应用程序,
HttpClientInitializer =凭证

});
$ b $ *获取日历列表* /
var calList = service.CalendarList.List()。Execute()。Items;
var myCalendar = calList.First(@c => @ c.Id == userAccountEmail);

/ * CREATE EVENT * /
var event1 = new Event()
{
Kind =calendar#event,
Summary =Calendar事件通过API,
描述=以编程方式创建,
状态=确认,
组织者=新的Event.OrganizerData(){
电子邮件= userAccountEmail
},
Start = new EventDateTime()
{
DateTime = DateTime.Now.AddDays(1)
},
End = new EventDateTime()
{
DateTime = DateTime.Now.AddDays(1).AddHours(1)
},
ColorId =6,
Reminders = new Event.RemindersData()
{
UseDefault = false,
Overrides = new List< EventReminder>(
new [] {
new EventReminder()
{
Method =popup,
分钟= 60
}
})
}
};

event1 = service.Events.Insert(event1,myCalendar.Id).Execute();
Console.WriteLine(创建的事件ID:{0},event1.Id);


/ *加入列表活动* /
Console.WriteLine(calendar id = {0},myCalendar.Id);
var events = service.Events.List(myCalendar.Id).Execute();
foreach(event.Items中的var @ event)
{
Console.WriteLine(Event ID:{0},ICalUID:{1},@ event.Id,@event。 ICalUID);
Console.WriteLine(Name:{0},@ event.Summary);
Console.WriteLine(Description:{0},@ event.Description);
Console.WriteLine(状态:{0},@ event.Status);
Console.WriteLine(Color:{0},@ event.ColorId);
Console.WriteLine(Attendees:{0},@ event.Attendees == null?:@ event.Attendees.Select(a => a.Email).ToString());
Console.WriteLine(Kind:{0},@ event.Kind);
Console.WriteLine(Location:{0},@ event.Location);
Console.WriteLine(Organizer:{0},@ event.Organizer.Email);
Console.WriteLine(Recurrence:{0},@ event.Recurrence == null?no recurrence:String.Join(,,@ event.Recurrence));
Console.WriteLine(Start:{0},@ event.Start.DateTime == null?@ event.Start.Date:@ event.Start.DateTime.ToString());
Console.WriteLine(End:{0},@ event.End.DateTime == null?@ event.End.Date:@ event.End.DateTime.ToString());
Console.WriteLine(Reminders:{0},@ event.Reminders.UseDefault.Value?Default:Not defailt,+
(@ event.Reminders.Overrides == null? no overrides:String.Join(,,@ event.Reminders.Overrides.Select(reminder => reminder.Method +:+ reminder.Minutes)))
);
Console.WriteLine(=====================);
}

Console.ReadKey();



static void Main(string [] args)
{
Connect();
}
}
}

生成的输出如下所示:

 通过OAuth2服务帐户的日历示例
创建的事件ID:jkits4dnpq6oflf99mfqf1kdo0
日历ID =我@ testdomain。 com
事件ID:1logvocs77jierahutgv962sus,ICalUID:1logvocs77jierahutgv962sus@google.com
名称:test event
描述:test description2
状态:已确认
颜色:
参加者:
种类:日历#活动
位置:位置2
主办单位:me@testdomain.com
复发:RRULE:FREQ =每周; BYDAY = TH
开始日期: 2014-07-31
结束于:2014-08-01
提醒:不是defailt,电子邮件:10,弹出:10
============== =======
事件ID:1logvocs77jierahutgv962sus_20140814,ICalUID:1logvocs77jierahutgv962sus@google.com
名称:测试事件已更新
描述:test description2
状态:已确认
颜色:
参加者:
种类:日历#事件
位置:loc ation2
主办单位:me@testdomain.com
复发:无复发
开始日期:2014-08-14
结束时间:2014-08-15
提醒:未设置默认值,电子邮件:10
=====================
事件ID:974hqdhh8jhv5sdobkggmdvvd8,ICalUID:974hqdhh8jhv5sdobkggmdvvd8@google.com
名称:一小时活动
描述:测试描述
状态:确认
颜色:7
参加者:
种类:日历#活动
位置:会议室租用,Broadway,255 The Bdwy,Broadway,NSW 2007,Australia
主办单位:me@testdomain.com
复发:无复发
开始日期:1/08/2014 10:00:00 AM
结束时间:1/08/2014 11:00:00 AM
提醒:默认
=====================
事件ID:jkits4dnpq6oflf99mfqf1kdo0,ICalUID:jkits4dnpq6oflf99mfqf1kdo0@google.com
名称:通过API的日历事件
描述:以编程方式创建
状态:已确认
颜色:6
参加者:
种类:日历#活动
地点:$ b​​ $ b主办单位:me@testdomain.com
复发:无复发
开始日期:2/08/2014 12:30:50 PM
结束日期:2/08/2014 1:30:50 PM
提醒:不是defailt,弹出:60
=====================

第一个事件是经常性的每周全天事件系列。
第二个是更新第一个单个事件(具有相同的UID)。
三是一小时的单项活动。
最后一个是由上面的代码创建的。



希望这可以帮助他人节约时间。


I'm trying to use service account to sync calendars from Dynamics CRM software to Google. During this I faced lack of documentation on google API for .net, especially regarding authorization. Most of Google samples can't be even compiled because of outdated libraries and classes used.

So I found some example over interned and receive error. Could someone please look on my sample and tell what am I doing wrong?

Preparatory steps:

  1. I created a project in my private Google account.
  2. In project developer console, under APIS & AUTH -> Credentials, I generated Service Account. Then clicked on "Generate P12 key" and downloaded the .p12 file.
  3. Under APIS & AUTH -> APIs, switched on "Calendar API"

Then created console app and managed to install OAuth and Calendar nuget packages. There are:

  1. Google APIs Auth Client Library, Google.Apis.Auth 1.8.1
  2. Google APIs Client Library, Google.Apis 1.8.1
  3. Google APIs Core Client Library, Id: Google.Apis.Core 1.8.1
  4. Google.APIs.Calendar.v3 Client Library, Google.Apis.Calendar.V3 1.8.1.860

There is a code found and adapted to my needs:

using System;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Calendar.v3;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;

namespace CrmToGoogleCalendar
{
    class Program
    {

        static void Connect()
        {
            var certificate = new X509Certificate2("My Project-ee7facaa2bb1.p12", "notasecret", X509KeyStorageFlags.Exportable);


            var serviceAccountEmail = "506310960175-q2k8hjl141bml57ikufinsh6n8qiu93b@developer.gserviceaccount.com";
            var userAccountEmail = "<my email>@gmail.com";
            var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) 
                {
                    User = userAccountEmail,
                    Scopes = new[] { CalendarService.Scope.Calendar }
                }
                .FromCertificate(certificate));

            var service = new CalendarService(new BaseClientService.Initializer()
            {
                ApplicationName = "Test calendar sync app",
                HttpClientInitializer = credential

            });

            var calList = service.CalendarList.List().Execute().Items;


            foreach (var cal in calList)
            {
                Console.WriteLine(cal.Id);
            }
        }


        static void Main(string[] args)
        {
            Connect();
        }
    }
}

The communication with Google API which I see in the app and Fiddler is:

Request :

Host: HTTPS accounts.google.com, URL: /o/oauth2/token
Assertion: long binary string
grant_type: urn:ietf:params:oauth:grant-type:jwt-bearer

Response:

HTTP/1.1 400 Bad Request Content-Type: application/json Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: Fri, 01 Jan 1990 00:00:00 GMT Date: Thu, 24 Jul 2014 06:12:18 GMT X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Server: GSE Alternate-Protocol: 443:quic Transfer-Encoding: chunked

1f { "error" : "invalid_grant" } 0

Please help and thanks in advance!

解决方案

After some investigations I found, that Google API does not work as expected with your personal account @gmail.com. You should have organization domain account in Google in format you@your_organisation_domain

Then, what is also pretty confusing, there is documentation at Google Drive API page, with "Delegate domain-wide authority to your service account" section not mentioned at Calendar API page. There are 7 steps in the section, are required to be done.

BTW with personal account administration site admin.google.com is even unavailable. So it's impossible to perform these 7 steps with @gmail.com account.

Then, when client is authorised in Google Apps Admin Console > Security > Advanced settings > Manage OAuth Client access the code starts to work.

There is a code that works for me:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Calendar.v3;
using Google.Apis.Calendar.v3.Data;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;

namespace CrmToGoogleCalendar
{
    class Program
    {

        static void Connect()
        {
            Console.WriteLine("Calendar via OAuth2 Service Account Sample");

            var certificate = new X509Certificate2("My MC Project-3f38defdf4e4.p12", "notasecret", X509KeyStorageFlags.Exportable);
            var serviceAccountEmail = "795039984093-c6ab1mknpediih2eo9cb70mc9jpu9h03@developer.gserviceaccount.com";
            var userAccountEmail = "me@testdomain.com"; 
            var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail) 
                {
                    User = userAccountEmail,
                    Scopes = new[] { CalendarService.Scope.Calendar }
                }
                .FromCertificate(certificate));

            var service = new CalendarService(new BaseClientService.Initializer()
            {
                ApplicationName = "Test calendar sync app",
                HttpClientInitializer = credential

            });

            /* Get list of calendars */
            var calList = service.CalendarList.List().Execute().Items;
            var myCalendar = calList.First(@c => @c.Id == userAccountEmail);

            /* CREATE EVENT */
            var event1 = new Event()
                {
                    Kind = "calendar#event",
                    Summary = "Calendar event via API",
                    Description = "Programmatically created",
                    Status = "confirmed",
                    Organizer = new Event.OrganizerData() {
                        Email = userAccountEmail
                    },
                    Start = new EventDateTime()
                        {
                            DateTime = DateTime.Now.AddDays(1)
                        },
                    End = new EventDateTime()
                    {
                        DateTime = DateTime.Now.AddDays(1).AddHours(1)
                    },
                    ColorId = "6",
                    Reminders = new Event.RemindersData()
                        {
                            UseDefault = false,
                            Overrides = new List<EventReminder>(
                                new [] {
                                    new EventReminder()
                                        {
                                            Method = "popup",
                                            Minutes = 60
                                        }
                                })
                        }
                };

            event1 = service.Events.Insert(event1, myCalendar.Id).Execute();
            Console.WriteLine("Created event Id: {0}", event1.Id);


            /* ENLIST EVENTS */
            Console.WriteLine("calendar id={0}", myCalendar.Id);
            var events = service.Events.List(myCalendar.Id).Execute();
            foreach (var @event in events.Items)
            {
                Console.WriteLine("Event ID: {0}, ICalUID: {1}", @event.Id, @event.ICalUID);
                Console.WriteLine("  Name: {0}", @event.Summary);
                Console.WriteLine("  Description: {0}", @event.Description);
                Console.WriteLine("  Status: {0}", @event.Status);
                Console.WriteLine("  Color: {0}", @event.ColorId);
                Console.WriteLine("  Attendees: {0}", @event.Attendees == null ? "" : @event.Attendees.Select(a => a.Email).ToString());
                Console.WriteLine("  Kind: {0}", @event.Kind);
                Console.WriteLine("  Location: {0}", @event.Location);
                Console.WriteLine("  Organizer: {0}", @event.Organizer.Email);
                Console.WriteLine("  Recurrence: {0}", @event.Recurrence == null ? "no recurrence" : String.Join(",", @event.Recurrence));
                Console.WriteLine("  Start: {0}", @event.Start.DateTime == null ? @event.Start.Date : @event.Start.DateTime.ToString());
                Console.WriteLine("  End: {0}", @event.End.DateTime == null ? @event.End.Date : @event.End.DateTime.ToString());
                Console.WriteLine("  Reminders: {0}", @event.Reminders.UseDefault.Value ? "Default" : "Not defailt, " + 
                    (@event.Reminders.Overrides == null ? "no overrides" : String.Join(",", @event.Reminders.Overrides.Select(reminder => reminder.Method + ":" + reminder.Minutes)))
                    );
                Console.WriteLine("=====================");
            }

            Console.ReadKey();
        }


        static void Main(string[] args)
        {
            Connect();
        }
    }
}

The output produced looks so:

Calendar via OAuth2 Service Account Sample
Created event Id: jkits4dnpq6oflf99mfqf1kdo0
calendar id=me@testdomain.com
Event ID: 1logvocs77jierahutgv962sus, ICalUID: 1logvocs77jierahutgv962sus@google.com
  Name: test event
  Description: test description2
  Status: confirmed
  Color: 
  Attendees: 
  Kind: calendar#event
  Location: location2
  Organizer: me@testdomain.com
  Recurrence: RRULE:FREQ=WEEKLY;BYDAY=TH
  Start: 2014-07-31
  End: 2014-08-01
  Reminders: Not defailt, email:10,popup:10
=====================
Event ID: 1logvocs77jierahutgv962sus_20140814, ICalUID: 1logvocs77jierahutgv962sus@google.com
  Name: test event updated
  Description: test description2
  Status: confirmed
  Color: 
  Attendees: 
  Kind: calendar#event
  Location: location2
  Organizer: me@testdomain.com
  Recurrence: no recurrence
  Start: 2014-08-14
  End: 2014-08-15
  Reminders: Not defailt, email:10
=====================
Event ID: 974hqdhh8jhv5sdobkggmdvvd8, ICalUID: 974hqdhh8jhv5sdobkggmdvvd8@google.com
  Name: One hour event
  Description: test description
  Status: confirmed
  Color: 7
  Attendees: 
  Kind: calendar#event
  Location: Meeting Room Hire, Broadway, 255 The Bdwy, Broadway, NSW 2007, Australia
  Organizer: me@testdomain.com
  Recurrence: no recurrence
  Start: 1/08/2014 10:00:00 AM
  End: 1/08/2014 11:00:00 AM
  Reminders: Default
=====================
Event ID: jkits4dnpq6oflf99mfqf1kdo0, ICalUID: jkits4dnpq6oflf99mfqf1kdo0@google.com
  Name: Calendar event via API
  Description: Programmatically created
  Status: confirmed
  Color: 6
  Attendees: 
  Kind: calendar#event
  Location: 
  Organizer: me@testdomain.com
  Recurrence: no recurrence
  Start: 2/08/2014 12:30:50 PM
  End: 2/08/2014 1:30:50 PM
  Reminders: Not defailt, popup:60
=====================

First event is recurrent weekly whole day event series. Second is updated single event of the first (has the same UID). Third is single event for one hour. The last is created by code above.

Hope this will help others to economy their time.

这篇关于Google API OAuth2,服务帐户,“错误” :“invalid_grant”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆