読者です 読者をやめる 読者になる 読者になる

O365でアプリケーション登録→APIアクセスしようとして

はまったわー

やりたいこと

  1. Office365を契約
  2. AzureADにアプリケーションを登録
  3. アプリケーションのアプリケーションID,秘密鍵を使ってアクセストークンを取得
  4. プログラムからアクセス

1. Office365を契約,AzureADにサインアップ

O365はE5を契約。

Office 365 Enterprise E5

サインアップ後、裏でデプロイされたAzureADにアプリケーション登録しようとAzureクラシックポータルにアクセスするが、AzureADサインアップ時にエラーになる。

パターン1. サインアップでエラー

電話による認証、クレジットカードによる認証を進めたところ、サインアップでエラーになった。原因不明。

パターン2. 電話による本人確認でエラー

そんな事を繰り返していたら、電話認証で番号を入れたタイミングで「アカウントを確認できませんでした。サポートにお問い合わせください。 」というエラーが出るようになった。想像だが、同じ電話番号で何度も認証していたらこのエラーが出るのではないか。証拠として、適当な電話番号を入力したときはエラーが出ずに認証コード入力画面になった(その番号の人、すいません)

2. AzureADにアプリケーションを登録

AzureADにアプリケーション登録をする手順は3つあるようです。

  1. Azureクラシックポータルから登録
  2. Azureポータル(以前、プレビューと言われていたものから登録)
  3. Office 365 ユーザーとエンタープライズ ユーザーのサインインを可能にする – Microsoft ID プラットフォームから登録

1.は今までのセオリーだったもの。

2について。最近、AzureクラシックポータルからAzureポータルへの機能移転が進んでおり、旧来Azureクラシックポータルでやっていたアプリ登録もAzureポータルから出来るようになったようです。

Microsoft Azure Portal

左ペインのAzure Active directory -> アプリの登録 -> +追加からアプリを登録。適切な権限を付与してキーを作成する。ただし、この機能はプレビュー版なので動作が怪しい可能性があります。(今回は大丈夫だったぽい)

んで、3はいったいなんなの?という話ですが、どうやらMSは商用のOffice365も私用のOutlook.comも同じコードで開発できるよう、RESTのエンドポイントを統一し、組織アカウントでログインすれば商用O365を、個人アカウントでログインすれば、Outlook.com側を触るようなAPIを実装しているらしい。

v2.0 endpoint の OAuth を使った Client 開発 (Azure AD と MSA への対応) – Tsmatz

そのアプリ登録のフロントエンドが、上記リンクの「Microsoft ID プラットフォーム」というわけ。ここからアプリ登録すると、裏側の仕組みとしてはログインした組織アカウントのAzureADにアプリ登録されるだけ。しかも、現状では「Microsoft ID プラットフォーム」画面からはGraph API関連の権限しか付与できず、outlook APIの権限はコントロールできない様子。

将来的に、製品個別のAPIがGraph APIに統一されるのを見越せば、本命は「Microsoft ID プラットフォーム」なんだろうけど、現時点では特別にこれを使う理由はなさそうです。

認証API v1.0 と v2.0について

よくわかってないです。

3. アプリケーションのアプリケーションID,秘密鍵を使ってアクセストークン(認証トークン)を取得

認証API v1.0での認証手順

Office 365 API 入門 – Tsmatz

  1. 以下のフォーマットで認証エンドポイントにアクセス
  2. このようなレスポンスがあれば成功

当初、リダイレクトURLとホームページURLを不一致としていたら、認証コードが取れなくてめちゃくちゃハマった。リダイレクトURLを"https://portal.office.com"に設定していたせいかもしれないが…。以下のようなレスポンスしか返ってこなかった。

https://www.office.com/1/?auth=2&home=1&from=PortalLanding&trial=1&client-request-id=bd26c05d-26aa-4b80-aaa2-6d79d770e88c

ひとまずマニュアル通り、https://localhost/myapp宛にリダイレクトする設定にした。ここでもハマって、どこかのサンプルでhttp://localhost/myappをリダイレクト先に指定していたのでコピペしたら、実はhttpsでないと全て無効なURLとなってしまうらしいことが分かった。どこにも書いてないんですが…。

認証API v2.0での認証手順

Get Started with the Outlook REST APIs - Outlook Dev Center

https://login.microsoftonline.com/common/oauth2/v2.0/authorize

  1. 以下のフォーマットで認証エンドポイントにアクセス

https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=[クライアントID]&redirect_uri=[リダイレクトURL]]p&response_type=code&scope=[スコープ]]

スコープはこんな感じで指定する↓

v2.0 認証エンドポイント プレビューを使用した Office 365 API と Outlook.com API の認証 | MSDN

今回、自分で登録したカスタムアプリを認証API v2で認証しようとしたところ、ブラウザバーに

Application+[クライアントID]+is+not+supported+for+this+API+version.

という表記が返り、エラーとなってしまった。おそらく、アプリケーションにめちゃくちゃ権限を付与してしまい、その権限のうち1つが認証API v2ではノンサポだからではないか。…となると、認証APIのバージョンによって使える機能も違うという事?認証API 1.0専用の権限をアプリに付与してしまうと、認証API 2.0で許可されない?

ということで、認証API v1.0だけで進めることにします。

メモ:参考にした記事

v2が出て一年以内だからか、v1とv2が混在してるのでややこしい。

4. プログラムからアクセス

3.で取得した認証トークンを元に、postを投げてやる

$url = 'https://login.microsoftonline.com/common/oauth2/token'

$Body = @{
  "grant_type" = "authorization_code"
  "code" = [認証コード]
  "client_id" = [クライアントID]
  "client_secret" = [クライアント秘密鍵]
  "redirect_uri" = "https://localhost/myapp"
  "resource" = "https://outlook.office365.com/"
}

$ContentType = "application/x-www-form-urlencoded"

Invoke-RestMethod -uri $url -Method Post -Body $body -ContentType $ContentType

結果、

token_type     : Bearer
scope          : Calendars.Read Calendars.Read.All Calendars.Read.Shared Calendars.ReadWrite Calendars.ReadWrite.All Calendars.ReadWrite.Shared Contacts.Read Contacts.Read.All Contacts.Read.Shared Contacts.ReadWrite Contacts.ReadWrite.All Contacts.ReadWrite.Shared Directory.AccessAsUser.All Directory.Read.All 
                 Directory.ReadWrite.All email Exchange.Manage Files.Read Files.Read.All Files.Read.Selected Files.ReadWrite Files.ReadWrite.All Files.ReadWrite.AppFolder Files.ReadWrite.Selected full_access_as_user Group.Read.All Group.ReadWrite.All IdentityRiskEvent.Read.All Mail.Read Mail.Read.All Mail.Read
                 .Shared Mail.ReadWrite Mail.ReadWrite.All Mail.ReadWrite.Shared Mail.Send Mail.Send.All Mail.Send.Shared MailboxSettings.ReadWrite Notes.Create Notes.Read Notes.Read.All Notes.ReadWrite Notes.ReadWrite.All Notes.ReadWrite.CreatedByApp offline_access openid People.Read People.ReadWrite profile 
                 Reports.Read.All Sites.Read.All Sites.ReadWrite.All Tasks.Read Tasks.Read.Shared Tasks.ReadWrite Tasks.ReadWrite.Shared User.Read User.Read.All User.ReadBasic.All User.ReadWrite User.ReadWrite.All
expires_in     : 3600
ext_expires_in : 0
expires_on     : 1478335851
not_before     : 1478331951
resource       : https://outlook.office365.com/
access_token   : アクセストークン
refresh_token  : リフレッショトークン
id_token       : IDトークン

権限めっちゃついてるw 自分でつけたんだけど…。

注意

サンプルコードに"resource"の指定がなかったため抜かすと、

"error":"invalid_resource","error_description":"AADSTS50001: Resource identifier is not provided.\r\nTrace ID

みたいなエラーが出た。エラーコード"AADSTS50001"でググると以下のURLがヒット(ppt注意)

Cloud Authentication Troubleshooting and Recipes for Developers

結論としては、resourceの指定は必要でした。

疲れたので今日はここまで。