アプリにOutlook Calendar APIを統合する方法

著者
公開日

すべてのカレンダーを単一の API で統合する

単一の API であらゆるカレンダー プロバイダーをアプリに統合できる Unified Calendar API へのアクセスを得るために、Unified Calendar API のウェイトリストにご参加ください。

ウェイトリストに参加するクレジットカード不要!

前回の記事「Google Calendar API をアプリケーションに統合する方法」では、Google Calendar API をアプリケーションに統合するために開発者が従うべきすべての手順を解説しました。

本記事では、Azure でのアプリ登録、スコープ設定、検証、統合時の注意点、実際のユースケースを含め、Outlook Calendar API をアプリに統合する方法を説明します。

前提条件

このガイドでは、すでに Azure Active Directory へアクセス可能な Microsoft の Work アカウントまたは Developer アカウントをお持ちであることを前提としています。

ディレクトリ外でアプリケーションを作成する機能は廃止されています。ディレクトリをお持ちでない場合は、Microsoft 365 Developer Program に参加するか、Azure にサインアップしてください。

Outlook Calendar API をアプリに統合する手順

Step 1: Microsoft Azure ポータルにサインインする

Microsoft Azure Portal サインインページにアクセスし、サインインしてください。

Azure ポータルのページ

Sign in to the Microsoft Azure Portal

Step 2: 新しいアプリケーションを登録する

Microsoft Azure Portal にサインインしたら、以下を実行します。

  1. Azure Active Directory に移動

    Azure App Directory Home
  2. 検索バーで 「App Registrations」 を検索

    Search App Registrations
  3. 「App Registrations」 をクリック

    Click App Registrations
  4. 「New registration」 をクリック

    Click New Registration
  5. 必要事項を入力

    Azure Active Directory - Register the application
    1. Name: ユーザーに表示されるアプリケーション名を入力します。

    2. Supported account types: アプリの種類に応じて選択します(社内利用かマルチテナントか)。ここでは 「Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant)」 を選択します。これにより、Outlook.com ユーザーを含む任意の組織のユーザーがアプリを利用できます。

    3. Redirect URI: 任意。Web アプリの場合は OAuth レスポンスを受け取る URI(例: https://yourapp.com/auth/callback)を入力します。

    4. 「Register」 をクリック

    5. 登録後に表示される Application (client) IDDirectory (tenant) ID を控えてください。

      Application Created


Client ID と Tenant ID は安全な場所に保存し、通常は環境変数として管理してください。

Step 3: API の権限とクライアント シークレットを設定する

アプリ登録後、カレンダー権限を設定します。権限は OAuth フローで表示され、ユーザーは承認前にアプリのスコープを確認できます。

既定では User.Read 権限が付与されています。ユーザープロファイルの取得のみであればこのステップをスキップできます。

API Permissions を追加する手順

  1. 左側の 「Manage」 タブをクリック

  2. 「API Permissions」 をクリック

    Click API Permissions
  3. 「+ Add a permission」 をクリック

    Click _Add a permission_ button
  4. Microsoft Graph カードを選択

    Click the _Microsoft Graph_ card
  5. Delegated permissionsApplication permissions から選択

    Click _Delegated Permissions_
  6. 「Calendars」で検索し、必要な権限(例: Calendars.ReadWrite, Calendars.ReadWrite.Shared)を選択

    Search for _Calendars Permissions_

Step 4: クライアント シークレットを生成する

カレンダー操作はサーバー側で行うことを推奨するため、クライアント シークレットを生成します。

  1. 「Certificates & secrets」 タブをクリック

    Click the “Certificates & secrets tab”
  2. 「New client secret」 をクリック

    Click “New client secret”
  3. 説明と有効期限を入力

    Enter a description and an expiration date

生成後はシークレットを再表示できません。必ずコピーして安全な場所(例: .env)に保管してください。

Step 5: ブランディングと検証

Branding & Properties セクションで、ロゴや説明、利用規約 URL などを設定できます。これは任意ですが、承認画面を洗練させるために推奨されます。マルチテナント アプリでは publisher-verified が必須となり、未検証の場合は他テナントのユーザーが承認できないことがあります。

Branding & Properties screen

Step 6: Outlook Graph API に慣れる

アプリを設定したら、Microsoft Calendar Graph API を確認し、イベントの作成・更新・削除などのエンドポイントに慣れておきましょう。

Step 7: すべてのカレンダー プロバイダーを単一 API で統合できるサービスの検討

Microsoft Graph API は十分にドキュメント化されていますが、Unified Calendar API を利用すれば、すべてのカレンダー プロバイダーを 1 つの API で統合できます。これにより、複数のプロバイダーごとの違いや制限を気にせずに開発できます。

OneCal Unified Calendar API

OneCal Unified Calendar API Landing Page

Outlook Calendar 認可フローの例

以下のフローチャートは、ユーザーが Outlook Calendar をアプリに接続するシンプルな OAuth フローを示しています。

Outlook OAuth 2.0 Flow

Microsoft OAuth2 フローの詳細は 公式ドキュメント を参照してください。

クライアント側 (UI)

const microsoftOauthUrl = getMicrosoftOAuthUrl()
<button href="microsoftOauthUrl" rel="noopener noreferrer"> Connect Outlook Calendar </button>

export const SCOPES = [
 "openid",
 "email",
 "profile",
 "offline_access",
 "Calendars.ReadWrite",
 "User.Read",
];

export interface ClientState {
 session: Session;
returnUrl?: string;
}

export function stateToB64(session: ClientState): string {
 return encode(JSON.stringify(session));
}

export function getMicrosoftOAuthUrl(
state: ClientState,
) {
 const nonce = uuid();
 const TENANT_ID = process.env.NEXT_PUBLIC_MICROSOFT_TENANT_ID;
 const params = new URLSearchParams({
 client_id: process.env.MICROSOFT_CLIENT_ID || "",
 redirect_uri: `${getHostName()}/api/connect/microsoft`,
 response_type: "code id_token",
 scope: SCOPES.join(" "),
 prompt: "consent",
 response_mode: "form_post",
 state: stateToB64(state),
nonce,
});
 return `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/authorize?${params}`;
}

  • prompt パラメータは login none consent select_account のいずれかです。

  • response_modequery fragment form_post のいずれかです。ここでは form_post を使用し、Microsoft からリダイレクト URI へ POST されるようにしています。

API 側 (バックエンド)

次に、Outlook からコードとスコープを受け取りトークンに交換する API ハンドラーを作成します。ここでは zod を使用しています。

const successSchema = z.object({
 code: z.string(),
 state: z.string(),
 id_token: z.string(),
 session_state: z.string().optional(),
});

const errorSchema = z.object({
 error: z.string(),
 error_description: z.string().optional(),
});
type ErrorParams = z.infer<typeof errorSchema>;

const querySchema = z.union([successSchema, errorSchema]);

function isError(query: Record<string, any>): query is ErrorParams {
 return Boolean(query.error);
}

const microsoftHandler: NextApiHandler = async (req, res) => {
 try {
 const result = querySchema.parse(req.body);
 if (isError(result)) {
 const q = new URLSearchParams({
 error: "ACCESS_DENIED",
 provider: CalendarProvider.MICROSOFT,
});

 console.error({ result });
 return res.redirect(302, `/?${q}`);
}

 const { session, returnUrl } = stateFromB64(result.state);
 const { email } = decodeIdToken(result.id_token);
 const { access_token, refresh_token, expires_in, scope } =
 await exchangeCodeForTokens(result.code);

 const connection = await upsertConnection(
{
email,
 accessToken: access_token,
 refreshToken: refresh_token,
 expiresInSeconds: expires_in,
 status: ConnectionStatus.ACTIVE,
 provider: CalendarProvider.MICROSOFT,
 scopes: scope,
 reminderCount: 0,
 lastRemindedAt: null,
},
session.user
);

 const q = new URLSearchParams({
 cid: connection.id,
});
 if (returnUrl) q.append("returnUrl", returnUrl);

res.redirect(302, returnUrl ? returnUrl : `/calendars/microsoft?${q}`);
} catch (e: any) {
 let error = JSON.stringify(e);

 const querystr =
 typeof req.query === "string" ? req.query : JSON.stringify(req.query);

 const q = new URLSearchParams({
error,
 provider: CalendarProvider.MICROSOFT,
});
 return res.redirect(302, `/?${q}`);
}
};

export default microsoftHandler;

コード交換などのユーティリティ関数も用意しておくことを推奨します。

const TENANT_ID = process.env.MICROSOFT_TENANT_ID;

export async function exchangeCodeForTokens(code: string) {
 const data = new FormData();
data.append("client_id", process.env.MICROSOFT_CLIENT_ID || "");
data.append("scope", SCOPES.join(" "));
data.append("code", code);
data.append("redirect_uri", `${getHostName()}/api/connect/microsoft`);
data.append("grant_type", "authorization_code");
data.append("client_secret", process.env.MICROSOFT_CLIENT_SECRET || "");

 try {
 const result = await fetch(
 `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`,
{
 method: "POST",
 body: data,
}
);

 const json = await result.json();
 if (json.error) throw json;

 const parsed = responseSchema.parse(json);
 return parsed;
} catch (e) {
 console.error("Exchange failed");
 throw e;
}
}

Outlook Calendar API 統合時の注意点

  • 検証には時間がかかることがある

    Microsoft Teams は日々多数のアプリ申請を処理しています。申請時にはすべての詳細を入力し、ロードマップで検証期間を考慮してください。

  • 必要最小限のスコープのみ要求する

    不要な権限は申請を難しくし、ユーザーの混乱を招きます。必要な権限だけをリクエストしましょう。

  • Webhook は期限切れになるため更新が必要

    カレンダー変更を監視する場合、数時間ごとに期限切れ前の購読を更新するバッチジョブを実装してください。

  • レート制限とスロットリング

    Microsoft には厳格な制限があります。一括取得を避けアプリ内でレート制御を行い、いわゆる「MailboxConcurrency」エラーを回避します。

スコープ (Scope)制限 (Limit)備考 (Notes)
メールボックスごと<br>(アプリ ID & メールボックス)10,000 requests / 10 min
同時 4 requests
いわゆる “MailboxConcurrency” エラー
アップロード150 MB 合計 PATCH/POST/PUT / 5 min
メールボックスあたり
大きな ICS や添付ファイルで発生
Global Graph130,000 requests / 10 s
アプリ全体
大規模 SaaS のバックフィルで稀に発生
リトライ方針429503/504Retry-After を確認し指数的バックオフ連続リクエストでは Graph API は引き続きスロットリング

  • タイムゾーンの落とし穴

    Outlook ではユーザーが任意のタイムゾーン文字列を入力できるため、想定外のフォーマットに備えてください。

  • 同意 & 権限の問題
    Calendars.ReadWrite はユーザーデリゲートですが、テナントによっては管理者の同意が必要です。「管理者の承認が必要」 エラーを検出し、ユーザーに管理者へ依頼するフローを案内しましょう。

OneCal Unified Calendar API で全カレンダープロバイダーを統合

OneCal は 2022 年以来、主要カレンダープロバイダー間で数十億件のイベントを同期してきました。私たちの経験から生まれた OneCal Unified Calendar API により、開発者はカレンダーに関する課題に何百時間も費やすことなく、機能開発や成長に集中できます。

Unified Calendar API 待機リストに参加して、リリース時に通知を受け取り、早期価格と割引をお得にご利用ください。