Como integrar a API do Outlook Calendar no seu aplicativo

Autores
Publicado em

No nosso último artigo sobre como integrar a API do Google Calendar ao seu aplicativo, explicamos todas as etapas que um desenvolvedor precisa seguir para integrar a API do Google Calendar ao seu aplicativo.

Neste artigo, explicaremos como integrar a API do Outlook Calendar ao seu aplicativo, incluindo a configuração do Registro de Aplicativo no Azure, configuração de escopos, verificação, armadilhas de integração e exemplos do mundo real.

Pré-requisitos

Este guia presume que você já possui uma conta Microsoft Work ou Developer com acesso ao Azure Active Directory.

Observe que a capacidade de criar aplicativos fora de um diretório foi descontinuada. Caso você não tenha um diretório, deve participar do Programa de Desenvolvedores Microsoft 365 ou se inscrever no Azure.

Como usar e integrar a API do Outlook Calendar ao seu aplicativo

Etapa 1: Faça login no Portal do Microsoft Azure

Acesse a Página de login do Portal do Microsoft Azure e faça login.

A página do Portal do Microsoft Azure.

Sign in to the Microsoft Azure Portal

Etapa 2: Registre um novo aplicativo

Após fazer login no Portal do Microsoft Azure:

  1. Navegue até Azure Active DirectoryAzure App Directory Home
  2. Pesquise por “App Registrations” na barra de buscaSearch App Registrations
  3. Clique em “App Registrations”Click App Registrations
  4. Clique em “New registration”Click New Registration
  5. Preencha os campos obrigatórios:Azure Active Directory - Register the application
    1. O primeiro campo é o Nome do seu aplicativo, que é o nome exibido para os usuários.
    2. Em seguida, você deve selecionar os tipos de conta suportados. A seleção será diferente dependendo do tipo de aplicativo que você está desenvolvendo (uso interno ou multi-tenant). Para este exemplo, selecionarei “Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant)”, pois isso garante que usuários de qualquer organização (incluindo usuários do Outlook.com) possam usar meu aplicativo. Isso é ideal para aplicativos SaaS ou qualquer aplicativo multi-tenant.
    3. Insira o Redirect URI: Isso é opcional, pois pode não ser necessário dependendo do tipo de aplicativo que você está construindo. Se você estiver desenvolvendo um aplicativo web, provavelmente precisará disso, pois este Redirect URI é o URI para onde o Azure enviará as respostas do OAuth. No menu suspenso “Select a platform”, selecione Web, depois preencha o campo Redirect URI (por exemplo, https://yourapp.com/auth/callback). Para o fluxo de autenticação do lado do servidor, usar um redirect URI web é apropriado. Certifique-se de que o domínio inserido seja acessível e esteja sob seu controle.
    4. Clique em “Register”
    5. Após clicar no botão “Register”, o Azure Active Directory criará seu aplicativo, e você será direcionado para a próxima página, onde poderá copiar o Client ID e o Tenant ID. O Application (client) ID é um GUID que identifica seu app. O Directory (tenant) ID nem sempre é necessário, pois na maioria dos casos, para apps multi-tenant, você usará o endpoint common. Você pode usar o tenant ID para testes em seu próprio tenant.

Certifique-se de salvar os campos Client ID e Tenant ID em um local seguro. Normalmente, eles são armazenados como variáveis de ambiente.

Etapa 3: Configurar as permissões da API

Após registrar seu aplicativo, é hora de configurar as permissões do calendário. Essas permissões são solicitadas durante o fluxo de OAuth, e o usuário pode ver quais são os escopos do seu aplicativo antes de aprovar e conceder acesso aos calendários.

Por padrão, sua aplicação recebe a permissão “User.Read”. Caso tudo o que você queira seja fazer login e ler o perfil do usuário, pode pular esta etapa.

Para adicionar permissões da API, siga estas etapas:

  1. Clique na aba “Manage” na barra lateral esquerda.
  2. Clique em “API Permissions”.Click API Permissions
  3. Clique no botão “+ Add a permission”.Click _Add a permission_ button
  4. Encontre o card “Microsoft Graph” (geralmente é o primeiro no painel à direita que aparece após clicar em “Add a permission”).Click the _Microsoft Graph_ card
  5. Escolha entre “Delegated permissions” e “Application permissions”. As permissões delegadas são úteis quando seu aplicativo precisa de acesso à API como o usuário conectado. As permissões de aplicativo podem ser usadas quando seu aplicativo é executado como um serviço em segundo plano sem um usuário conectado. Para este exemplo, usarei “Delegated Permissions”.Click _Delegated Permissions_
  6. Pesquise por “Calendars”: Esta busca mostrará todas as permissões relacionadas a calendários. Escolha as permissões que permitem que seu aplicativo funcione corretamente. Na maioria dos casos, você desejará selecionar “Calendars.ReadWrite” e “Calendars.ReadWrite.Shared” (se precisar de acesso a calendários compartilhados). Observe que os escopos de Calendário geralmente não exigem consentimento de administrador por padrão, pois são escopos delegados ao usuário, mas tenha em mente que algumas organizações restringem o consentimento do usuário. Se um usuário de um tenant externo não puder conceder consentimento, um administrador daquele tenant deverá conceder o consentimento para seu app (geralmente por meio de um prompt ou URL de consentimento administrativo).Search for _Calendars Permissions_

Etapa 4: Ativar tokens de ID

Esta etapa não se aplica a todos os aplicativos, mas caso você queira acessar informações do perfil do usuário como nome, e-mail ou URL da foto de perfil, é necessário ativar a opção ID Tokens, em Manage -> Authentication.

Isso permite que seu app identifique o usuário assim que ele se conecta ao calendário, sem precisar fazer outra chamada à API.

Enable ID Tokens option

Nota: Ativar os tokens de ID é obrigatório se você estiver usando a API Unificada de Calendário da OneCal.

Etapa 5. Gerar um Client Secret

Recomendamos que as operações de calendário (escrita, leitura, atualização, etc) sejam feitas do servidor; por isso você precisa gerar um client secret.

Para gerar um Client Secret, siga estas etapas:

  1. Clique na aba “Certificates & secrets”Click the “Certificates & secrets tab”
  2. Clique em “New client secret”Click “New client secret”
  3. Insira uma descrição e uma data de expiraçãoEnter a description and an expiration date

Após gerar o client secret, certifique-se de copiá-lo e armazená-lo em um local seguro (geralmente no seu arquivo .env).

Observe que você não poderá visualizar ou copiar o client secret depois, então certifique-se de copiá-lo antes de sair da página.

Etapa 6. Marca e Verificação

Na seção Branding & Properties do registro do app, você pode definir um logotipo e informações (descrição do app, URL dos termos de serviço, etc.). Isso é opcional, mas recomendado para uma tela de consentimento mais profissional. É essencial definir um domínio do publicador (normalmente seu domínio personalizado, verificado no Azure AD) para evitar que o app apareça como “não verificado” ao solicitar consentimento. Para apps multi-tenant, a Microsoft agora exige que os apps sejam verificados como publicadores para uso amplo. Se seu app não estiver verificado, usuários de fora do seu tenant podem ser impedidos de conceder consentimento devido às políticas de segurança introduzidas em novembro de 2020.

Branding & Properties screen

Etapa 7. Familiarize-se com a API Outlook Graph

Após configurar o aplicativo e preencher todas as informações, podemos começar a explorar a Microsoft Calendar Graph API, para nos familiarizarmos com as APIs específicas para criar, atualizar e excluir eventos.

Etapa 8. Considere usar uma API Unificada de Calendário para integrar todos os provedores de calendário com uma única API

Embora a Microsoft Graph API esteja razoavelmente bem documentada, recomendamos usar um produto de API Unificada de Calendário que permite integrar todos os provedores de calendário por meio de uma única API.

Ao usar uma API Unificada de Calendário, você tem o benefício de implementar uma única API em seu aplicativo e oferecer suporte a todos os provedores de calendário, independentemente de suas limitações ou diferenças de API.

Outro benefício de usar uma única API para todos os calendários é que você não precisa manter várias APIs de calendário, lidar com mudanças que quebram integrações ou casos extremos que nunca havia previsto.

OneCal Unified Calendar API

OneCal Unified Calendar API Landing Page

Exemplo de fluxo de autorização do Outlook Calendar

O diagrama abaixo ilustra um fluxo OAuth simples do Outlook Calendar que permite que os usuários conectem seus calendários do Outlook ao seu aplicativo.

Outlook OAuth 2.0 Flow

Acesse a página de documentação do Microsoft OAuth2 Flow para saber mais sobre o fluxo OAuth2 da Microsoft.

Client Side (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}`;
}

  • O parâmetro “prompt” pode ter um dos quatro valores: loginnoneconsent e select_account.
  • O “response_mode” pode ter os valores queryfragment ou form_post. Escolhemos form_post porque ele informa à Microsoft que envie uma solicitação POST para nosso redirect URI (no servidor).

API Side (Backend)

A seguir, vamos construir o handler da API, responsável por obter o código e os escopos do servidor do Outlook e trocá-los por tokens.

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

Recomendamos também ter funções utilitárias como esta para trocar o código por tokens.

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

Armadilhas ao integrar a API do Outlook Calendar

  • A verificação pode demorar e ser frustrante às vezes: Tenha em mente que milhares (senão milhões) de desenvolvedores usam o Outlook diariamente, então a equipe da Microsoft processa milhares de submissões de aplicativos por dia. Certifique-se de preencher todos os detalhes ao enviar para revisão e leve em consideração esse tempo no seu cronograma.
  • Solicite apenas os escopos estritamente necessários: A equipe da Microsoft é muito rigorosa em suas revisões, então certifique-se de solicitar apenas o que é necessário para seu app executar suas funcionalidades. Isso facilitará a aprovação e deixará a interface de consentimento mais clara para o usuário, que pode se confundir ao ver escopos desnecessários.
  • Webhooks expiram, certifique-se de renová-los: Caso esteja registrando webhooks para acompanhar mudanças no calendário, configure um job de segundo plano a cada poucas horas para renovar assinaturas de webhooks que irão expirar.
  • Limites de taxa e restrições: A Microsoft impõe limites rigorosos de taxa. Evite buscar itens um por um e implemente controle de taxa nas chamadas do seu app para evitar os famosos erros “MailboxConcurrency”. A tabela a seguir explica os limites:

Escopo

Limite

Observações

Por caixa de correio (par App ID + caixa)

10.000 requisições / 10 min e 4 requisições simultâneas

O famoso erro “MailboxConcurrency”.

Upload

150 MB total de PATCH/POST/PUT a cada 5 min por caixa.

Pode ocorrer ao anexar arquivos ICS grandes ou anexos.

Global Graph

130.000 requisições / 10 s por app em todos os tenants.

Raro, mas grandes preenchimentos em massa podem disparar isso.

Etiqueta de Repetição

Em 429 ou 503/504 procure o cabeçalho Retry-After, faça backoff exponencial.

A Graph API continuará limitando se você insistir com requisições a cada segundo.

  • Problemas com fusos horários: No Outlook, o usuário pode digitar manualmente seu próprio fuso horário (sim, isso mesmo), então certifique-se de tratar esse caso também.
  • Problemas com consentimento e permissões: Como mencionado na configuração dos escopos da aplicação, Calendars.ReadWrite é um escopo delegado, mas alguns tenants não permitem consentimento de usuários. Esteja preparado para o erro “admin consent required” e ofereça um fluxo amigável de “Peça ao seu administrador”.

Integre todos os provedores de calendário ao seu app com a API Unificada de Calendário da OneCal

Integrações de calendário são nossa especialidade. Desde 2022, sincronizamos bilhões de eventos entre todos os principais provedores de calendário, e nossos links de agendamento são usados por milhares de profissionais ao redor do mundo.

As lições que aprendemos lidando com todas as APIs de calendário nos motivaram a criar a API Unificada de Calendário da OneCal, permitindo que nossos usuários evitem gastar centenas de horas com problemas relacionados a calendário e foquem em implementar funcionalidades que realmente beneficiem seus produtos e seu crescimento.

Cadastre-se na OneCal Unified Calendar API para testar nossa Unified API e integrar facilmente vários provedores de calendário usando uma única API.

FAQ

Que tipo de conta eu preciso para usar a API do Outlook Calendar?

Uma conta Microsoft Work ou Developer com acesso ao Azure Active Directory.

Quais escopos de permissão devo adicionar para acesso total ao calendário?

Adicione Calendars.ReadWrite (e Calendars.ReadWrite.Shared se precisar de calendários compartilhados) no Microsoft Graph.

Por que definir um domínio do publicador e marca?

A verificação de publicador e a tela de consentimento personalizada evitam que seu app apareça como “não verificado” e agora são exigidas para a maioria dos apps multi-tenant.

Com que frequência devo renovar as assinaturas de webhooks do Outlook?

Os webhooks de calendário do Graph expiram em poucas horas, então é necessário agendar um job de fundo para renovar qualquer assinatura prestes a expirar.

A API do Outlook Calendar suporta notificações push?

Sim. Crie uma assinatura do Microsoft Graph para receber notificações de alteração em vez de fazer polling.

Existe uma maneira mais fácil de integrar calendários do Outlook, Google e iCloud ao meu aplicativo?

Sim. Uma API Unificada de Calendário como a OneCal encapsula todos os principais provedores em uma única interface JSON consistente. Usando a API Unificada de Calendário da OneCal, você não precisa desenvolver nem manter integrações separadas para cada provedor de calendário.