Google Calendar API返回invalid_grant和错误的请求

Google Calendar API返回invalid_grant和错误的请求

问题描述:

在我的开发环境中,我有一个用户刚刚收到以下范围的OAuth令牌.

In my development environment, I have a user that I just received an OAuth Token for the following scopes.

一切都很好,我为用户存储了令牌.然后,我请求列出用户的日历,并且收到请求无效的invalid_grant.我用另一个用户的令牌尝试了相同的请求(也在我的开发环境中),它可以正常工作.

Everything looks fine and I store the token for the user. I then request to list the calendars for the user and I get the invalid_grant with bad request. I try the same request with another user's token (also in my development environment) and it works correctly.

我最初只有第一个作用域设置,即写级别访问.这就是所有现有令牌的创建对象.在测试期间,我添加了其他范围.

I originally had only the first scope setup, which is write level access. That is what all existing tokens were created with. During my testing, I added the other scopes.

我已尝试为项目中的Google API更新NuGet软件包.

I have tried updating the NuGet packages for Google APIs in my project.

这是我正在上课的班级.

This is my class that is making the calls.

public class GoogleCalendarAdapter : ICalendarAdapter {
    #region attributes
    private readonly ISiteAuthTokenQueryRepository _tokenRepo;
    private readonly GoogleCalendarSettings        _settings;

    private const string APPNAME = "REDACTED";

    private const string ACL_OWNER = "owner";
    private const string ACL_WRITER = "writer";
    #endregion

    #region ctor
    public GoogleCalendarAdapter(ISiteAuthTokenQueryRepository tokenRepo,
                                 GoogleCalendarSettings        settings) {
        _tokenRepo = tokenRepo;
        _settings  = settings;
    }
    #endregion

    #region methods
    private GoogleAuthorizationCodeFlow BuildAuthorizationCodeFlow() {
        return new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer() {
            ClientSecrets = BuildClientSecrets(),
            Scopes        = BuildScopeList()
        });
    }

    private CalendarService BuildCalendarService(SiteAuthToken token) {

        return new CalendarService(new BaseClientService.Initializer() {
                ApplicationName       = APPNAME,
                HttpClientInitializer = BuildUserCredential(token)
        });
    }

    private ClientSecrets BuildClientSecrets() {
        return new ClientSecrets() {
            ClientId = _settings.ClientId,
            ClientSecret = _settings.ClientSecret
        };
    }

    private string[] BuildScopeList() {
        return new [] { CalendarService.Scope.Calendar };
    }

    private UserCredential BuildUserCredential(SiteAuthToken token) {
        TokenResponse responseToken = new TokenResponse() {
            AccessToken  = token.AccessToken,
            RefreshToken = token.RefreshToken
        };

        return new UserCredential(BuildAuthorizationCodeFlow(), APPNAME, responseToken);
    }

    public async Task<List<Cal>> GetAllWritableCalendars(Guid siteGuid) {
        SiteAuthToken token = await GetToken(siteGuid);
        CalendarService svc = BuildCalendarService(token);

        IList<CalendarListEntry> calendars = svc.CalendarList
                                                .List()
                                                .Execute()
                                                .Items;

        return calendars.Where(c => c.AccessRole.Equals(ACL_OWNER,  StringComparison.CurrentCultureIgnoreCase) ||
                                    c.AccessRole.Equals(ACL_WRITER, StringComparison.CurrentCultureIgnoreCase))
                        .Select(c => new Cal() {
                            Id   = c.Id,
                            Name = c.Summary
                        })
                        .OrderBy(o => o.Name)
                        .ToList();
    }

    public async Task<Cal> GetCalendar(Guid siteGuid, string calendarId) {
        SiteAuthToken token = await GetToken(siteGuid);
        CalendarService svc = BuildCalendarService(token);

        CalendarListEntry entry = svc.CalendarList
                                     .Get(calendarId)
                                     .Execute();

        Cal retVal = new Cal() {
            Id   = entry.Id,
            Name = entry.Summary
        };

        return retVal;
    }

    private async Task<SiteAuthToken> GetToken(Guid siteGuid) {
        SiteAuthToken retVal = await _tokenRepo.GetSiteAuthToken(siteGuid, Constants.OAUTH_PROVIDER_GOOGLE);

        if (retVal == null) {
            throw new ApplicationException($"Could not find a SiteAuthToken for specified site (SiteGuid: {siteGuid})");
        }

        return retVal;
    }

    #endregion
}

在您所描述的情况下,对我有极大帮助的事情是使用Google Developer OAuth游乐场.默认情况下,您可以使用OAuthPlayground本身作为客户端来获取授权(并观看流量).但是,诀窍是进入[设置]齿轮并选中[x]复选框.使用您自己的OAuth凭据,然后尝试授权您的客户端.IMO这是一个非常有用的调试工具,我想确保您了解它.

Something that's helped me immensely in situations like the one you describe is to use the Google Developer OAuth Playground. By default, you can obtain the grant (and watch the traffic) using OAuthPlayground itself as the client. But then the trick is to go in the [Settings] gear and check the box for [x] Use your own OAuth Credentials and try and authorize your client. IMO this is a very useful debugging tool and I wanted to make sure you are aware of it.