Come integrare Outlook Calendar API nella tua app

Autori
Pubblicato il

Integra tutti i calendari tramite un’unica API

Iscriviti alla nostra lista d’attesa per la Unified Calendar API per ottenere l’accesso alla nostra Unified Calendar API, che ti consente di integrare tutti i provider di calendari nella tua app tramite un’unica API.

Iscriviti alla lista d’attesaNon è richiesta la carta di credito!

Nel nostro ultimo articolo su come integrare l’API di Google Calendar nella tua applicazione, abbiamo spiegato tutti i passaggi che uno sviluppatore deve seguire per integrare l’API di Google Calendar nella propria applicazione.

In questo articolo spiegheremo come integrare l’API di Outlook Calendar nella tua app, inclusa la configurazione della registrazione dell’app su Azure, l’impostazione degli ambiti, la verifica, le insidie dell’integrazione e alcuni esempi reali.

Prerequisiti

Questa guida presuppone che tu disponga già di un account Microsoft Work o Developer con accesso ad Azure Active Directory.

Tieni presente che la possibilità di creare applicazioni al di fuori di una directory è stata deprecata. Se non hai una directory, dovresti aderire al Microsoft 365 Developer Program o iscriverti ad Azure.

Come usare e integrare l’API di Outlook Calendar nella tua app

Passaggio 1: Accedi al Portale di Microsoft Azure

Visita la pagina di accesso al Portale di Microsoft Azure ed effettua l’accesso.

La pagina del Portale di Microsoft Azure.

Sign in to the Microsoft Azure Portal

Passaggio 2: Registra una nuova applicazione

Dopo aver effettuato l’accesso al Portale di Microsoft Azure:

  1. Vai su Azure Active Directory

    Azure App Directory Home
  2. Cerca “App Registrations” nella barra di ricerca

    Search App Registrations
  3. Clicca su “App Registrations”

    Click App Registrations
  4. Clicca su “New registration”

    Click New Registration
  5. Compila i campi richiesti:

    Azure Active Directory - Register the application

    1. Il primo campo è il Nome dell’applicazione, ovvero il nome visibile agli utenti.

    2. Poi seleziona i tipi di account supportati. La scelta varia a seconda del tipo di applicazione che stai sviluppando (uso interno o multi-tenant). Per questo esempio selezionerò “Accounts in any organizational directory (Any Microsoft Entra ID tenant – Multitenant)”, così gli utenti di qualsiasi organizzazione (compresi gli utenti Outlook.com) potranno usare la mia app. Questo è l’ideale per applicazioni SaaS o multi-tenant.

    3. Inserisci l’URI di reindirizzamento: opzionale, può non servire a seconda del tipo di applicazione. Se stai sviluppando una web app, molto probabilmente ne avrai bisogno, poiché questo URI è dove Azure invierà le risposte OAuth. Nel menu “Select a platform” scegli Web, quindi compila il campo Redirect URI (per esempio, https://yourapp.com/auth/callback). Per i flussi di autenticazione server-to-server, un URI web va bene. Assicurati che il dominio inserito sia raggiungibile e sotto il tuo controllo.

    4. Clicca su “Register”.

    5. Dopo il clic su “Register”, Azure Active Directory creerà la tua applicazione e verrai reindirizzato alla pagina successiva, dove potrai copiare Client ID e Tenant ID. L’Application (client) ID è un GUID che identifica la tua app. Il Directory (tenant) ID non è sempre necessario; per app multi-tenant di solito si usa l’endpoint common. Puoi usare il tenant ID per i test nel tuo tenant.

      Application Created

Salva in un luogo sicuro Client ID e Tenant ID, di solito come variabili d’ambiente.

Passaggio 3: Configura le autorizzazioni API

Dopo aver registrato l’app, è il momento di configurare i permessi del calendario. Questi permessi vengono mostrati nel flusso OAuth e l’utente può vedere gli ambiti della tua app prima di concedere l’accesso ai propri calendari.

Per impostazione predefinita, alla tua app è assegnato il permesso “User.Read”. Se tutto ciò che ti serve è firmare l’utente ed effettuare la lettura del profilo, puoi saltare questo passaggio.

Per aggiungere permessi API, segui questi passaggi:

  1. Clicca sulla scheda “Manage” nella barra laterale sinistra.

  2. Clicca su “API Permissions”.

    Click API Permissions
  3. Clicca sul pulsante “+ Add a permission”.

    Click _Add a permission_ button
  4. Trova la scheda “Microsoft Graph” (di solito è la prima nella finestra a destra).

    Click the _Microsoft Graph_ card
  5. Scegli tra “Delegated permissions” e “Application permissions”. Le autorizzazioni delegate servono quando l’app ha bisogno di accesso all’API come l’utente connesso. Le application permissions vanno bene se l’applicazione gira come servizio in background senza utente connesso. Per questo esempio userò “Delegated Permissions”.

    Click _Delegated Permissions_
  6. Cerca “Calendars”: vedrai tutti i permessi relativi al calendario. Seleziona quelli necessari al corretto funzionamento della tua app. Nella maggior parte dei casi vorrai selezionare “Calendars.ReadWrite” e “Calendars.ReadWrite.Shared” (se ti serve l’accesso ai calendari condivisi). Gli scope del calendario non richiedono normalmente il consenso dell’amministratore, perché sono delegati all’utente, ma alcune organizzazioni limitano il consenso degli utenti. Se un utente di un tenant esterno non può consentire, un amministratore di quel tenant dovrà concedere il consenso per la tua app.

    Search for _Calendars Permissions_

Passaggio 4: Genera un Client Secret

Consigliamo di eseguire le operazioni di calendario (scrittura, lettura, aggiornamento, ecc.) dal server; per questo è necessario generare un client secret.

Per generare un Client Secret:

  1. Clicca sulla scheda “Certificates & secrets”

    Click the “Certificates & secrets tab”
  2. Clicca su “New client secret”

    Click “New client secret”
  3. Inserisci una descrizione e una data di scadenza

    Enter a description and an expiration date

Dopo aver generato il client secret, copialo e conservalo in un luogo sicuro (di solito nel tuo file .env).

Non potrai più visualizzare o copiare il client secret in seguito, quindi copialo prima di lasciare la pagina.

Passaggio 5: Branding e Verifica

Nella sezione Branding & Properties della registrazione dell’app puoi impostare un logo e altre informazioni (descrizione, URL dei termini di servizio, ecc.). È facoltativo ma consigliato per un’esperienza di consenso più professionale. È essenziale impostare un Publisher Domain (tipicamente il tuo dominio personalizzato, verificato in Azure AD) per evitare che l’app venga mostrata come “non verificata” quando gli utenti concedono il consenso. Per le app multi-tenant, Microsoft richiede ora che le app siano publisher-verified per un uso esteso. Se la tua app non è verificata dal publisher, gli utenti esterni al tuo tenant potrebbero essere bloccati dal concedere il consenso a causa delle politiche di sicurezza introdotte a novembre 2020.

Branding & Properties screen

Passaggio 6: Familiarizza con l’Outlook Graph API

Dopo aver configurato l’applicazione e completato tutte le informazioni, puoi iniziare a esplorare la Microsoft Calendar Graph API per conoscere meglio le API specifiche per creare, aggiornare e cancellare eventi.

Passaggio 7: Valuta l’uso di un servizio di API Calendario Unificata per integrare tutti i provider con un’unica API

Anche se la Microsoft Graph API è ben documentata, consigliamo l’uso di un prodotto di API Calendario Unificata che ti permette di integrare tutti i provider di calendario tramite un’unica API.

Usando una API Calendario Unificata, implementi una sola API nella tua applicazione e supporti tutti i provider di calendario, indipendentemente dalle loro limitazioni o differenze di API.

Un altro vantaggio di utilizzare un’unica API per tutti i calendari è che non devi manutenere diverse API, occuparti di breaking changes o gestire casi limite inaspettati.

OneCal Unified Calendar API

OneCal Unified Calendar API Landing Page

Esempio di flusso di autorizzazione per Outlook Calendar

Il diagramma seguente illustra un semplice flusso OAuth di Outlook Calendar che consente agli utenti di collegare il loro Outlook Calendar alla tua app.

Outlook OAuth 2.0 Flow

Visita la pagina di documentazione sul flusso OAuth2 di Microsoft per saperne di più.

Lato client (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}`;
}

  • Il parametro “prompt” può assumere uno tra quattro valori: login, none, consent e select_account.

  • Il parametro “response_mode” può avere i valori query, fragment o form_post. Abbiamo scelto form_post perché istruisce Microsoft a inviare una richiesta POST al nostro redirect URI (sul server).

Lato API (Backend)

Ora costruiamo l’handler API, responsabile di ottenere il code e gli scope dal server Outlook e scambiarli con i token.

In questo esempio usiamo zod per la validazione.

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;

Funzioni di utilità simili si consigliano per scambiare il code con i token, ecc.

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;
}
}

Insidie dell’integrazione dell’API di Outlook Calendar

  • La verifica può richiedere tempo ed essere frustrante: Tieni presente che migliaia, se non milioni, di sviluppatori usano Outlook ogni giorno, quindi il team Microsoft gestisce migliaia di invii di applicazioni quotidianamente. Compila tutti i dettagli durante l’invio per la revisione e includi nel tuo roadmap il tempo per il processo di verifica.

  • Richiedi solo gli scope strettamente necessari: Il team Microsoft è molto scrupoloso nella revisione, quindi richiedi solo ciò che è indispensabile al funzionamento della tua app. Questo non solo faciliterà l’approvazione, ma aiuterà anche gli utenti quando concedono l’accesso: sarebbe confuso se la tua app chiedesse permessi non correlati alle funzionalità reali.

  • I webhooks scadono: ricordati di rinnovarli: Se registri webhooks per monitorare le modifiche al calendario, imposta un job in background che ogni poche ore rinnovi le sottoscrizioni prossime alla scadenza.

  • Rate limiting e throttling: Microsoft applica regole di throttling molto rigide; evita il recupero dei dati un elemento alla volta e implementa il rate limiting nelle tue chiamate per non incorrere nei famosi errori “MailboxConcurrency”. La tabella seguente illustra i limiti:

    AmbitoLimiteNote
    Per mailbox (app ID & mailbox)10 000 richieste / 10 min e 4 richieste concorrentiErrore “MailboxConcurrency”.
    Upload150 MB totali PATCH/POST/PUT per 5 min per mailboxPossibile quando si allegano grandi file ICS o allegati.
    Global Graph130 000 richieste / 10 s per app su tutti i tenantRaro, ma back-fill SaaS estesi possono attivarlo.
    Retry etiquetteSu 429 o 503/504 controlla l’header Retry-After, esegui backoff esponenzialeLa Graph API continua a limitare se la colpisci ogni secondo.

  • Problemi di fuso orario: In Outlook un utente può digitare manualmente il proprio fuso orario (capisci dove voglio arrivare…), quindi gestisci anche questo caso.

  • Problemi di consenso e permessi: Come detto nella configurazione degli scope, Calendars.ReadWrite è delegato all’utente, ma molti tenant consentono il consenso utente, altri no. Preparati a gestire l’errore “admin consent required” e proponi un flusso di “Chiedi al tuo admin”.

Integra tutti i provider di calendario nella tua app con l’OneCal Unified Calendar API

Le integrazioni di calendario sono il nostro pane quotidiano. Dal 2022 abbiamo sincronizzato miliardi di eventi tra tutti i principali provider, e i nostri link di pianificazione sono usati da migliaia di professionisti in tutto il mondo.

Le lezioni apprese lavorando con tutte le API dei calendari hanno dato vita alla OneCal Unified Calendar API, che permette ai nostri utenti di evitare centinaia di ore di problemi legati ai calendari per concentrarsi sulle funzionalità che fanno crescere il prodotto.

Iscriviti alla nostra API Calendario Unificata per essere avvisato non appena lanceremo il prodotto e approfittare di prezzi e sconti dedicati ai primi utenti.