调用Google Calendar API时触发GoogleJsonResponseException 401 Unauthorized错误
That 401 error is a common gotcha when working with the Google Calendar API—here's why it’s happening and how to fix it:
Root Cause
A simple API key only works for accessing public, unauthenticated resources in Google APIs. Google Calendar data (especially user-specific calendars like your own "primary" calendar) is private, so the API needs to verify you have permission to access it. API keys don’t provide user identity or authorization, hence the "Login Required" message.
Solutions
1. Use OAuth 2.0 Authentication (For Private/User-Specific Calendars)
This is the standard approach for accessing private calendar data. Here’s how to set it up:
- Open the Google Cloud Console, navigate to your project, and go to APIs & Services > Credentials.
- Create an OAuth 2.0 Client ID (select "Desktop app" as the application type if you’re running a local script).
- Download the client secret JSON file and place it in your project directory.
- Update your code to use the OAuth flow instead of the API key. Here’s a Java example matching your error’s stack trace:
import com.google.api.client.auth.oauth2.Credential; 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.jackson2.JacksonFactory; import com.google.api.client.util.store.FileDataStoreFactory; import com.google.api.services.calendar.Calendar; import com.google.api.services.calendar.CalendarScopes; import java.io.FileReader; import java.util.Collections; public class CalendarApiExample { private static final String APPLICATION_NAME = "Your App Name"; private static final JacksonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); private static final String TOKENS_DIRECTORY_PATH = "tokens"; public static void main(String[] args) throws Exception { // Load client secrets from downloaded JSON GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new FileReader("client_secret.json")); // Build OAuth flow with read-only scope (adjust to CALENDAR for write access) GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( GoogleNetHttpTransport.newTrustedTransport(), JSON_FACTORY, clientSecrets, Collections.singleton(CalendarScopes.CALENDAR_READONLY)) .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH))) .setAccessType("offline") // Store token for future use .build(); // Trigger browser-based authorization LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build(); Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user"); // Initialize Calendar service with authenticated credential Calendar service = new Calendar.Builder(GoogleNetHttpTransport.newTrustedTransport(), JSON_FACTORY, credential) .setApplicationName(APPLICATION_NAME) .build(); // Example: Fetch upcoming events from primary calendar com.google.api.services.calendar.model.Events events = service.events().list("primary") .setMaxResults(10) .setTimeMin(new com.google.api.client.util.DateTime(System.currentTimeMillis())) .setOrderBy("startTime") .setSingleEvents(true) .execute(); } }
2. Use API Key Only For Public Calendars
If you’re targeting a public calendar (like a global holiday calendar), ensure:
- The calendar is marked public in Google Calendar settings (share it with "Make available to public" and grant "See all event details" permissions).
- Your API key is restricted to the Google Calendar API (in Cloud Console, edit your API key and add the Calendar API under "Restrict key to APIs").
- Use the public calendar ID in your request (e.g.,
en.usa#holiday@group.v.calendar.google.comfor US holidays).
Key Takeaway
API keys are great for public data, but any private user-specific data in Google APIs requires OAuth 2.0 to authenticate and authorize access. The OAuth flow will prompt you to log in with your Google account and grant permissions to your app, which resolves the 401 error.
内容的提问来源于stack exchange,提问作者nairavs

