Office 365は、Outlook(Exchagne)、OneDriveおよびVideoにREST APIが用意されています。
この記事では、Office 365 REST APIを利用してOutlookのリソースにアクセスする手順について確認した内容をまとめてみました。

API関連の情報ソース

APIを利用を始めるにあたって、以下のようなドキュメントを参考にしました。

REST API全体のリファレンスについては、Office 365 API reference、利用可能なOutlookのリソースについては、Resource reference for the Mail, Calendar, Contacts, and Task REST APIsで確認できます。

日本語版は、Office 365 API リファレンスがあります。

その他の参考情報としては

以下の公式ブログなどが参考になります。

Office 365 APIの種類

Office Dev Center – Getting StartedにアクセスするとOffice 365でアプリを開発する方法がいくつか紹介されています。

Office 365 APIは、のエンドポイントを利用することができます。

  • Office 365 APIs: メール、カレンダー、連絡先、ファイルへアクセスするREST API
  • Office Add-ins (formerly Apps for Office): Officeへアドオンするアプリ
  • SharePoint Add-Ins (formerly known as Apps for SharePoint): SharePointアプリ
  • Office 365 Connectors for Groups

また、これまでいくつかにわかれていたAPI群は、Microsoft Graphとして、より多くのAPIが一つのエンドポイント https://graph.microsoft.com/ で利用可能になりました。

作成するRuby on Railsアプリについて

この記事で作成していくのは、Office 365のREST APIへアクセしOutlookのメール一覧を取得し表示するRuby on Railsのアプリケーションです。
このサンプルは、Exchange Dev Blogに紹介されていた公式のサンプルでソースコードはGithubに公開されています。

Exchange Dev Blog: Ruby on Rails and Office 365 Tutorial
Outlook Dev Center: Write a Ruby on Rails app to get Outlook mail
Github: jasonjoh/o365-tutorial

Office 365 REST APIへのアクセスは、Azure ADのOAuth 2.0を利用します。
Office 365 APIとAzure ADの関係は、Azure ADはAuthorization Serverとして働き、Office 365 APIはAzure ADに登録されたResource Serverとなっています。

oauth-to-azure-ad-and-office365-api
この図は、ドキュメント「Azure AD の認証シナリオ」の「デーモンまたはサーバー アプリケーション対 Web API」の図を書き直したものです、こちらのドキュメントも参照ください。

Azure ADでのOAuthの説明は、Azure AD での OAuth 2.0も参考になります。

また、補足になりますが、この記事の以下の内容は2015年の中頃に検証していたメモをまとめたもので、Azure AD v2.0エンドポイントが公開される前の内容になります。
上記ブログのリンクを参照すると現在(2016.4)はv2エンドポイントベースに書き換えられています。

v2エンドポイントについては、Microsoft アカウント ユーザーおよび Azure AD ユーザーによる単一アプリでのサインインを参照ください。

では、以下Azure ADへアプリケーションを登録するところから説明していきます。

Azure ADサブスクリプションの登録

Office 365は、ドメインを作成した際に裏でAzure ADが用意されますが、Azure ADを管理するためにはAzureのサブスクリプションに紐付ける必要があります。
詳しくは、「Azure サブスクリプションを Azure Active Directory に関連付ける方法」、「Azure でのリソース アクセスについて」を参照ください。

Office 365の管理センターを開き、[管理センター] > [Azure AD]を選択します
o365-azure-ad-01

サブスクリプションを持っている、またはサブスクリプションを作成するWindowsアカウントでサインインします
o365-azure-ad-02

Azureサブスクリプションが有効化されていない場合は、以下の画面が表示されます
o365-azure-ad-04

[Azure サブスクリプション]をクリックすると、Azureサインナップフォームが表示されます
windows-azure-signup
無料の Azure Active Directory サブスクリプションの登録を参考にサインナップします。

サインナップ後は、以下のページが表示されるので、しばらく待ちます
o365-azure-ad-06

準備が完了すると[サービスの管理を開始する]をクリック
o365-azure-ad-07

新しいAzureポータルが表示されます
Active Directoryを管理するためには[参照]から[Active Directory]を選択します。
o365-azure-ad-08

旧ポータルが表示されるので、ツアーウィザードを終わらせます
o365-azure-ad-09

既存のサブスクリプションにAzure ADを関連付ける手順は、「補足: Azure ADを既存のAzure ADサブスクリプションに接続する」を参照ください。

Azure ADディレクトリにアプリケーションを追加

Azure旧ポータルで[Active Directory]を表示すると、Office 365が登録されているディレクトリを確認できます。
active-directory-of-office365-domain-on-azure-potal

このディレクトリに、アプリケーションを追加します。
Manually Register an Office 365 API app in Azure AD(Office Dev Center)の手順に従って、Office 365のAzure ADにアプリを登録し、
クライアント ID とシークレットを生成するを実行して、アプリケーションのクライアントIDとシークレットを取得します。

ドメインをクリックして[アプリケーション]タブを選択します。
add-application-to-azure-ad
[追加]をクリックします。

add-application-to-azure-what-do-you-want-to-do
自分で開発するアプリケーションの場合は、[組織で開発中のアプリケーションを追加]を選択します

アプリケーション情報の指定
アプリケーションの名前を入力し、[WebアプリケーションやWEB API]を選択して[->](次へ)をクリックします

Office365_RoR_Tutorial_09
[サインオン URL]に「http://localhost:3000」、[アプリケーション ID / URL]は「https://.onmicrosoft.com/o365-tutorial」と入力しました。
[アプリケーション ID /URL]は、URI形式かつディレクトリ内で一意であれば任意の値で問題ありません。

右下のチェックアイコンをクリックして保存します。
アプリケーションが追加されました。
application-has-been-added-to-azure-ad

続いて、追加したアプリケーションの[構成]タブを開き、クライアントIDの確認、キーの生成およびOffice 365 Exchangeへのアクセス許可を設定していきます。

構成タブをスクロールするとクライアントIDが確認できます
application-configuration-show-client-id-and-secret
また、[キー]のプルダウンから[1 年]を選択して追加します
キーは、構成を保存すると生成されます

さらに、下までスクロールして、[他のアプリケーションに対するアクセス許可]の[アプリケーションの追加]ボタンをクリックします
select-permissions-to-other-application
[Office 365 Exchange Online]を選択して、右下のチェックアイコンをクリックして保存します。

select-permissions-to-office365-exchange-online
[Office 365 Exchange Online]の行[デリゲートされたアクセス許可]をクリックして[Read user mail]にチェックを入れます。

[保存]をクリックして設定を保存
o365-azure-ad-application-client-id-and-key
[キー]に生成され表示されます。
キーは生成直後のみ表示されるのでコピーして控えておきます。

以上で、Azure ADディレクトリへアプリを登録でき、実装に入る準備が整いました。

Railsアプリの作成

Railsプロジェクトを作成して、確認用にHttpサーバーを起動しておきます。

$ rails new o365-tutorial
$ cd o365-tutorial
$ rails server

トップページの作成

Welcomeページの置き換え
ApplicationControllerにhomeアクションを追加

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  def home
    # Display the login link.
    render html: '<a href="#">Log in and view my email</a>'.html_safe
  end
end

homeアクションをrootに割り当て

Rails.application.routes.draw do
  root 'application#home'
end

http://localhost:3000にアクセスして確認
Office365_RoR_Tutorial_01

OAuth2フローの実装

Gemfileにoauth2を追加し

gem 'oauth2'

bundle installを実行

$ bundle install

OAuth2コールバックを処理するコントローラーを追加します

$ rails generate controller Auth

[CONFIGURE]タブの[CLIEND ID]と[keys]に追加したシークレットの値をコピーして
CLIENT_IDとCLIENT_SECRETにセット

module AuthHelper

  # App's client ID. Register the app in Azure AD to get this value.
  CLIENT_ID = 'xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx'
  # App's client secret. Register the app in Azure AD to get this value.
  CLIENT_SECRET = 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy/as='

  # Generates the login URL for the app.
  def get_login_url
    client = OAuth2::Client.new(CLIENT_ID,
                                CLIENT_SECRET,
                                :site => "https://login.microsoftonline.com",
                                :authorize_url => "/common/oauth2/authorize",
                                :token_url => "/common/oauth2/token")

    login_url = client.auth_code.authorize_url(:redirect_uri => authorize_url)
  end
end

16行目は、後で追加するルーティング/authorizeを指定

get_login_urlメソッドを追加したAuthHelperをApplicationControllerから呼び出すように修正

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception
  include AuthHelper

  def home
    # Display the login link.
    login_url = get_login_url
    render html: "<a href='#{login_url}'>Log in and view my email</a>".html_safe
  end
end

RIDIRECT_URLに指定した/authorizeアクションを次に実装していきます

ルーティングを追加

Rails.application.routes.draw do
  root 'application#home'
  get 'authorize' => 'auth#gettoken'
end

Authヘルパーにアクセストークンを取得するメソッドを追加します

module AuthHelper
  ...
  # Exchanges an authorization code for a token
  def get_token_from_code(auth_code)
    client = OAuth2::Client.new(CLIENT_ID,
                                CLIENT_SECRET,
                                :site => "https://login.microsoftonline.com",
                                :authorize_url => "/common/oauth2/authorize",
                                :token_url => "/common/oauth2/token")

    token = client.auth_code.get_token(auth_code,
                                       :redirect_uri => authorize_url,
                                       :resource => 'https://outlook.office365.com')

    access_token = token.token
  end
end

アクションをコントローラに実装

class AuthController < ApplicationController
  def gettoken
    token = get_token_from_code params[:code]
    render text: token
  end
end

http://localhost:3000にアクセスして、Office 365アカウントでサインインすると以下のようにアクセストークンが取得できます
Office365_RoR_Tutorial_14

表示された文字列をコピーし、http://jwt.calebb.net/でアクセストークンを検証してみると、以下のようにログインしたユーザーの情報を含むJSONを確認できます
Office365_RoR_Tutorial_15

アクセストークンでREST APIを呼び出す

アクセストークンの取得ができたので、実際にOffice 365 REST APIにアクエスしてOutlookのメールを取得するコードを実装していきます。

メール操作用のコントローラを作成

$ rails generate controller Mail index

アクセストークンをセッションに入れて、MainController#indexへリダイレクトするようにAuth#gettokenアクションを修正

class AuthController < ApplicationController
  def gettoken
    token = get_token_from_code params[:code]
    session[:azure_access_token] = token
    redirect_to mail_index_url
  end
end

faradayをGemfileに追加して、bundle installする
faradayはREST API用の呼び出しに使うHttp Client

gem 'faraday'
$ bundle install

MailControllerのindexアクションを実装

class MailController < ApplicationController
  def index
    token = session[:azure_access_token]
    if token
      # If a token is present in the session, get messages from the inbox
      conn = Faraday.new(:url => 'https://outlook.office365.com') do |faraday|
        # Outputs to the console
        faraday.response :logger
        # Uses the default Net::HTTP adapter
        faraday.adapter  Faraday.default_adapter
      end

      response = conn.get do |request|
        # Get messages from the inbox
        # Sort by DateTimeReceived in descending orderby
        # Get the first 20 results
        request.url '/api/v1.0/Me/Messages?$orderby=DateTimeReceived desc&$select=DateTimeReceived,Subject,From&$top=20'
        request.headers['Authorization'] = "Bearer #{token}"
        request.headers['Accept'] = "application/json"
      end

      # Assign the resulting value to the @messages
      # variable to make it available to the view template.
      @messages = JSON.parse(response.body)['value']
    else
      # If no token, redirect to the root url so user
      # can sign in.
      redirect_to root_url
    end
  end
end

ビューは以下のとおり

<h1>My messages</h1>
<table>
  <tr>
    <th>From</th>
    <th>Subject</th>
    <th>Received</th>
  </tr>
  <% @messages.each do |message| %>
    <tr>
      <td><%= message['From']['EmailAddress']['Name'] %></td>
      <td><%= message['Subject'] %></td>
      <td><%= message['DateTimeReceived'] %></td>
    </tr>
  <% end %>
</table>

再度、http://localhost:3000にアクセスし認証すると、以下のようにメール一覧が表示されます
o365-ruby-on-rails-sample-show-mail-list

この後は、ログインユーザーのアクセストークン、更新トークンを保存して、更新トークンによるアクセストークンの再取得などを実装する必要があります。

補足: Azure ADを既存のAzure ADサブスクリプションに接続する

今回は、Office 365アカウントで新規にAzureサブスクリプションを登録しましたが、既存のAzureサブスクリプションにディレクトリにOffice 365のディレクトリを紐付けることができます。

公式ドキュメントでは、Azure サブスクリプションを Azure Active Directory に関連付ける方法Azure での Office 365 サブスクリプションのディレクトリの管理 「Microsoft アカウントを使用する Azure のサブスクリプションがある場合」に説明があります。

Azure クラシックポータルで、[ディレクトリ] > [カスタム作成]をクリック
o365-azure-ad-create-custom-directory

ディレクトリ [既存のディレクトリを使用]を選択して、[サインアウトする準備ができました]をチェックして右下のチェックアイコンをクリック
ディレクトリの追加 既存のディレクトリを使用

Azure サブスクリプションアカウントをサインアウトします
o365-azure-ad-connect-to-existing-azure-subscription-02

Office 365組織の管理者アカウントでログインし直すと、以下の画面が表示されます
o365-azure-ad-connect-to-existing-azure-subscription-03
[続行]をクリック
o365-azure-ad-connect-to-existing-azure-subscription-04
サインアウト後、Azureサブスクリプション アカウントでログインし直すと、Office 365ドメインが追加されていることが確認できます
o365-azure-ad-connect-to-existing-azure-subscription-05