calcom/cal.diy · warning · HttpError
You must grant all permissions to use this integration
Error message
You must grant all permissions to use this integration
What it means
After exchanging the code for tokens, the handler checks that every scope in `GOOGLE_CALENDAR_SCOPES` appears in `token.tokens.scope`. Google lets users uncheck individual scopes during consent; if any required calendar scope is missing, this throws `HttpError` **400** — but only when `!state?.fromApp`. When `fromApp` is set it redirects gracefully and returns instead. `add.ts` sets `prompt: "consent"` to force a fresh grant specifically to avoid stale partial grants.
Source
Thrown at packages/app-store/googlecalendar/api/callback.ts:60
if (!req.session?.user?.id) {
throw new HttpError({ statusCode: 401, message: "You must be logged in to do this" });
}
const { client_id, client_secret } = await getGoogleAppKeys();
const redirect_uri = `${WEBAPP_URL_FOR_OAUTH}/api/integrations/googlecalendar/callback`;
const oAuth2Client = new OAuth2Client(client_id, client_secret, redirect_uri);
if (code) {
const token = await oAuth2Client.getToken(code);
const key = token.tokens;
const grantedScopes = token.tokens.scope?.split(" ") ?? [];
// Check if we have granted all required permissions
const hasMissingRequiredScopes = GOOGLE_CALENDAR_SCOPES.some((scope) => !grantedScopes.includes(scope));
if (hasMissingRequiredScopes) {
if (!state?.fromApp) {
throw new HttpError({
statusCode: 400,
message: "You must grant all permissions to use this integration",
});
}
res.redirect(
getSafeRedirectUrl(state.onErrorReturnTo) ??
getSafeRedirectUrl(state?.returnTo) ??
`${WEBAPP_URL}/apps/installed`
);
return;
}
oAuth2Client.setCredentials(key);
const gcalCredentialData = buildCredentialCreateData({
userId: req.session.user.id,
key,
appId: "google-calendar",View on GitHub (pinned to 176037d0af)
Solutions
- Inform the user all scopes are required and restart the flow — `add.ts` already uses `prompt: "consent"` to force a clean grant; ensure that parameter reaches every install entry point.
- When starting OAuth, include `state.fromApp` or `state.onErrorReturnTo`/`returnTo` so partial-consent failures redirect gracefully instead of throwing.
- Verify the app in Google Cloud Console so consent isn't scoped down, and confirm `GOOGLE_CALENDAR_SCOPES` matches the scopes configured there.
Example fix
// before
if (hasMissingRequiredScopes) {
if (!state?.fromApp) {
throw new HttpError({ statusCode: 400, message: "You must grant all permissions to use this integration" });
}
res.redirect(...); return;
}
// after - also honor onErrorReturnTo/returnTo, consistent with the code-check guard above
if (hasMissingRequiredScopes) {
if (!state?.fromApp && !state?.onErrorReturnTo && !state?.returnTo) {
throw new HttpError({ statusCode: 400, message: "You must grant all permissions to use this integration" });
}
res.redirect(...); return;
} Defensive patterns
Strategy: validation
Type guard
// Verify the granted scopes cover everything required before treating the install as complete
function hasAllRequiredScopes(granted: string[], required: readonly string[]): boolean {
return required.every((s) => granted.includes(s));
}
// usage after token exchange:
const granted = token.tokens.scope?.split(" ") ?? [];
if (!hasAllRequiredScopes(granted, GOOGLE_CALENDAR_SCOPES)) {
// re-prompt with prompt=consent rather than dead-ending
} Prevention
- Always start OAuth with prompt=consent (as add.ts does) to force a fresh, full grant.
- Carry state.fromApp or onErrorReturnTo/returnTo so partial-consent failures redirect gracefully.
- Keep GOOGLE_CALENDAR_SCOPES in sync with the scopes configured on the Google Cloud app, and verify the app to avoid scope capping.
When it happens
Trigger: User unchecked one or more calendar scopes on Google's granular consent screen; Google granted only a subset; the app is unverified/testing and Google limited the granted scopes; consent cache returned an older, narrower grant than requested.
Common situations: End users deselecting 'See and download your calendars'; app in Google Cloud testing mode capping scopes; `GOOGLE_CALENDAR_SCOPES` changed but Google's consent cache returns the previous narrower grant; re-consent not forced.
Related errors
- `code` must be a string
- You must be logged in to do this
- Session user must have an email
- You must be logged in to do this
- Credentials for google_calendar not found.
AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12).
Data as JSON: /api/errors/97a7a9993b6a7aa0.
Report an issue: GitHub.