calcom/cal.diy · error · UnauthorizedException

Invalid Access token.

Error message

Invalid Access token.

What it means

Thrown by OutlookService.saveCalendarCredentialsAndRedirect, the OAuth-callback handler for Office 365. After Microsoft redirects back with an OAuth code, the handler resolves the calling user via tokensService.getAccessTokenOwnerId(accessToken); if no user maps to the supplied Cal platform access token, UnauthorizedException('Invalid Access token.') is raised before the code is exchanged for Graph credentials (getOAuthCredentials). This is the Outlook twin of error 380 in the Google service.

Source

Thrown at apps/api/v2/src/platform/calendars/services/outlook.service.ts:184

    redir?: string,
    isDryRun?: boolean
  ) {
    // if code is not defined, user denied to authorize office 365 app, just redirect straight away
    if (!code || code === "undefined") {
      return { url: redir || origin };
    }

    // if isDryRun is true we know its a dry run so we just redirect straight away
    if (isDryRun) {
      return { url: redir || origin };
    }

    const parsedCode = z.string().parse(code);

    const ownerId = await this.tokensService.getAccessTokenOwnerId(accessToken);

    if (!ownerId) {
      throw new UnauthorizedException("Invalid Access token.");
    }

    const office365OAuthCredentials = await this.getOAuthCredentials(parsedCode);

    const defaultCalendar = await this.getDefaultCalendar(office365OAuthCredentials.access_token);

    if (defaultCalendar?.id) {
      const alreadyExistingSelectedCalendar = await this.selectedCalendarsRepository.getUserSelectedCalendar(
        ownerId,
        OFFICE_365_CALENDAR_TYPE,
        defaultCalendar.id
      );

      if (alreadyExistingSelectedCalendar) {
        const isCredentialValid = await this.calendarsService.checkCalendarCredentialValidity(
          ownerId,
          alreadyExistingSelectedCalendar.credentialId ?? 0,
          OFFICE_365_CALENDAR_TYPE

View on GitHub (pinned to 176037d0af)

Solutions

  1. Re-authenticate with the Cal platform OAuth flow to obtain a fresh access token, then retry the Office 365 callback.
  2. Confirm the token being passed is the Cal platform access token (not the Microsoft OAuth code) and is delivered where the handler reads it.
  3. Ensure the deployment issuing the token and the deployment serving the callback are the same and share the signing secret/DB.

Example fix

// before
window.location.href = `${apiBase}/v2/calendars/office365/connect/callback?code=${msCode}`;

// after
// refresh calAccessToken first if it may have expired during consent
window.location.href = `${apiBase}/v2/calendars/office365/connect/callback?code=${msCode}`;
Defensive patterns

Strategy: validation

Validate before calling

async function ensureTokenOwner(tokensService, accessToken) {
  const ownerId = await tokensService.getAccessTokenOwnerId(accessToken);
  if (!ownerId) return { ok: false, reason: 'Invalid Access token.' };
  return { ok: true, ownerId };
}

Type guard

function isNonEmptyToken(t: unknown): t is string {
  return typeof t === 'string' && t.trim().length > 0 && t !== 'undefined';
}

Try / catch

try {
  await outlookService.saveCalendarCredentialsAndRedirect(code, accessToken, origin);
} catch (e) {
  if (e instanceof UnauthorizedException && e.message === 'Invalid Access token.') {
    // re-authenticate, then retry once
  } else throw e;
}

Prevention

When it happens

Trigger: The /v2/calendars/office365/connect/callback (or equivalent) is called with an accessToken that is expired, revoked, belongs to another environment, or was never sent; the token is sent in the wrong location (query vs Authorization header); the user took long enough on Microsoft's consent screen that the Cal access token expired before the callback.

Common situations: Long Microsoft consent flow outlasting the Cal access-token TTL; token issued by a different Cal deployment (env mismatch); client passed the OAuth code as the access token or vice-versa; clock skew on the API host.

Related errors


AI-assisted analysis of calcom/cal.diy@176037d0af (2026-08-12). Data as JSON: /api/errors/767277441f5cadd9. Report an issue: GitHub.