You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Google Auth库对接Calendar API时遇'type'字段缺失错误求助

解决Google Calendar API认证报错:'type'字段未指定

错误原因

你当前使用的GoogleCredentials.fromStream()方法是为服务账号凭证设计的,这类凭证会包含type字段(值为service_account)。但你的credentials.json是桌面/本地应用的OAuth 2.0客户端凭证(installed类型),格式不匹配,因此触发报错。

解决方案

需要使用Google API Client Library提供的GoogleClientSecrets来解析OAuth客户端凭证,再通过AuthorizationCodeFlow实现用户授权流程,同时持久化授权令牌避免重复授权。

步骤1:替换凭证加载逻辑

将原代码中加载凭证的部分替换为以下逻辑:

// 加载客户端凭证
InputStream in = GoogleCalendarExample.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
if (in == null) {
    throw new FileNotFoundException("Credentials file not found: " + CREDENTIALS_FILE_PATH);
}
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

// 创建授权流
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
        HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
        .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
        .setAccessType("offline")
        .build();

// 获取授权凭证
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
Credentials credentials = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");

步骤2:修改完整代码

更新后的完整GoogleCalendarExample类如下:

package pl.szylak.googleservices;

import com.google.api.client.auth.oauth2.Credentials;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.DateTime;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.calendar.Calendar;
import com.google.api.services.calendar.CalendarScopes;
import com.google.api.services.calendar.model.Event;
import com.google.api.services.calendar.model.EventDateTime;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.util.Collections;

public class GoogleCalendarExample {
    private static final String APPLICATION_NAME = "Google Calendar API Java Quickstart";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final String TOKENS_DIRECTORY_PATH = "tokens";
    private static final String CREDENTIALS_FILE_PATH = "/resources/credentials.json";
    private static final java.util.List<String> SCOPES = Collections.singletonList(CalendarScopes.CALENDAR);

    private static Calendar service;

    public static void main(String... args) throws IOException, GeneralSecurityException {
        // Build a new authorized API client service.
        final com.google.api.client.http.javanet.NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();

        // 加载客户端凭证并获取授权
        InputStream in = GoogleCalendarExample.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
        if (in == null) {
            throw new FileNotFoundException("Credentials file not found: " + CREDENTIALS_FILE_PATH);
        }
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build();

        LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
        Credentials credentials = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");

        service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credentials)
                .setApplicationName(APPLICATION_NAME)
                .build();

        // Call the Google Calendar API and add an event.
        addEvent();
    }

    private static void addEvent() throws IOException {
        Event event = new Event()
                .setSummary("Google I/O 2025")
                .setLocation("800 Howard St., San Francisco, CA 94103")
                .setDescription("A chance to learn more about Google's developer products.");

        EventDateTime start = new EventDateTime()
                .setDateTime(new DateTime("2025-05-28T09:00:00-07:00"))
                .setTimeZone("America/Los_Angeles");
        event.setStart(start);

        EventDateTime end = new EventDateTime()
                .setDateTime(new DateTime("2025-05-28T17:00:00-07:00"))
                .setTimeZone("America/Los_Angeles");
        event.setEnd(end);

        String calendarId = "primary";
        event = service.events().insert(calendarId, event).execute();
        System.out.printf("Event created: %s\n", event.getHtmlLink());
    }
}

关键说明

  • 依赖确认:确保你引入了google-api-client和google-api-client-jetty依赖,保证授权流程的类能正常加载。
  • 第一次运行:程序会自动打开浏览器,引导你完成Google账号授权,授权成功后令牌会保存到tokens目录,后续运行无需重复授权。
  • 令牌持久化:FileDataStoreFactory负责将授权令牌存储到本地文件,避免每次启动都重新授权。

内容的提问来源于stack exchange,提问作者Adrian Szyłak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 23:28:12