Spring'14で外部のOAuth APIへのアクセスが簡単になったよ、という話

# はじめに

Salesforceには「認証プロバイダ(Auth Provider)」とよばれる外部のプロバイダにSalesforceの認証を委譲する機能があるのですが、Salesforce Spring'14のアップデートではこれが OpenID Connectに対応するなど、機能が強化されています。

残念ながらOpenID Connectに対応しているプロバイダはGoogleなどまだ少数です。なのでほとんどのかたはOpenID Connectってなんじゃらほい？という状態かもしれません。

しかし、そんな方でも、OAuth2.0ならば聞いたことあるかもしれません。実は今回のOpenID Connect対応においては、OpenID Connectに未対応のOAuth2.0 APIにおいても一部利用することができます。APIにアクセスするためのOAuthアクセストークンの取得を認証プロバイダにおまかせしてしまうことができるのです。

# 今まで

Salesforceから外部のOAuth APIにアクセスするには、以下のようなフローをすべて自前で実装する必要がありました。

1. OAuthのClient ID, Client Secretなどを保管するカスタムSオブジェクトあるいはカスタム設定を作る
2. Apex Controllerを使って、APIのAuthorization URLにリダイレクトする
3. Apex Controller & Visualforce Pageを使ってコールバック用のページを作成する。
4. Authorization Codeをパラメータで受け取り、Client ID, Client Secretなどと共にToken URLにHTTPコールし、Access Tokenを受け取る
5. Access Tokenを現在のユーザに紐付けてSオブジェクト内に保管する

上記手順では、トークンやシークレットをオブジェクト内に保管することから、Sオブジェクトやカスタム設定の共有セキュリティ設定などを十分気を使わなければいけませんでした。また、上記には入っていませんが、アクセストークンのリフレッシュフローについても実装する必要がありました。

認証プロバイダについては、Facebook、JanRain、Salesforceなどを選べましたが、主にログインの委譲にのみ使われており、APIアクセスについては二の次でした。Facebookについては後述する[AuthTokenの仕組みを利用してFacebook Graph APIを使うことができました](https://developer.salesforce.com/page/Getting_Started_with_the_Force.com_Toolkit_for_Facebook,_Version_3.0)が、scopeが指定できないなどあまり有用とはいえませんでした。

今回、認証プロバイダが任意のOAuth2.0 APIのアクセストークン取得に対応したことによって、Force.comプラットフォームにアクセストークンの取得や保管についても任せることができるようになりました。

# 設定方法

## アプリの登録（APIプロバイダ側）

以下ではOAuth APIの例としてFoursquare APIのアクセストークンを取得することにします。

まずは、Foursquareにアプリの登録を行います。アプリの登録は [https://developer.foursquare.com/](https://developer.foursquare.com/) から登録できます。

アプリの名前は適当につけてください。登録の際にコールバックURL(Redirect URI)などのURLを指定する必要がありますが、まずは適当につけて保存しておきます。

アプリを登録すると、Client IDとClient Secretが割り与えられるので、この値をコピーしておきます。また、FoursquareのAuthorize URLおよびAccess Token URLの情報についても記載されているので、それもコピーしておきます（Authorize URLは `https://foursquare.com/oauth2/authorize` 、Access Token URLは `https://foursquare.com/oauth2/access_token` となっています）。

## 認証プロバイダの登録（Salesforce側）

続いて、Salesforceの認証プロバイダの登録画面に移ります。

まず、以下の画像のように、プロバイダタイプとして「OpenID Connect」を選択します。名前およびURL接頭辞に「Foursquare」と入力します。

コンシューマ鍵（Consumer Key）およびコンシューマの秘密（Consumer Secret）には、先ほど登録したアプリのClient IDおよびClient Secretをそれぞれ入力します。

承認エンドポイントおよびトークンエンドポイントには、Foursquare APIのAuthorize URLおよびAccess Token URLをそれぞれ入力します。

![authprovider.jpg](https://qiita-image-store.s3.amazonaws.com/0/6495/5ac15f5a-73ce-2428-8536-13769823c943.jpeg)

以上の入力が完了したら、保存ボタンを押します。

登録が完了すると、以下のように認証プロバイダの詳細画面が表示されます。詳細画面の下方にURLが表示されているのがわかります。

![fsprovider.png](https://qiita-image-store.s3.amazonaws.com/0/6495/0e322d92-604f-6766-6156-8db773aae7f0.png)

ここで、「コールバックURL」として表示されているURLをコピーし、再度Foursquareのアプリ管理画面にもどり、先ほど登録したアプリの設定編集を行います。Redirect URI(s)に設定されているURLを変更し、コピーしたコールバックURLの値に設定します。

## OAuthによる認可の開始

先程の認証プロバイダの詳細画面には、「Oauth専用初期化URL」というURLがあります。このURLにリダイレクトすることで、OAuthの認可フローが開始されます。

以下はFoursquareのOAuthトークンを取得して表示するだけのApex ControllerとVisualforceページです。Apex Controller では、`AuthToken` クラスの `getAccessToken()`というメソッドを利用して、現在のユーザのアクセストークンを取得し、Visualforceページ内でその内容を単純に出力しています。

### FoursquareController.cls

```java
public class FoursquareController{
    public AuthProvider provider { get; private set; }
	public String accessToken { get; private set; }
    
    public FoursquareController() {
        provider = [SELECT Id, DeveloperName FROM AuthProvider WHERE DeveloperName = 'Foursquare' LIMIT 1];
        accessToken = Auth.AuthToken.getAccessToken(provider.Id, 'open id connect');
    }
}
```

### FoursquareTestPage.page

```xml
<apex:page controller="FoursquareController">
    Provider ID: {!provider.Id}<br />
    Provider Name: {!provider.DeveloperName}<br />
    Foursquare Access Token: {!accessToken}<br />
    <a href="https://login.salesforce.com/services/auth/oauth/{!$Organization.Id}/{!provider.DeveloperName}?startURL=/apex/FoursquareTestPage">Start OAuth</a>
</apex:page>
```

まだアクセストークンを取得していない場合は、Foursquare Access Tokenは空欄になります。「Start OAuth」リンクをクリックすると、OAuthの認可フローが始まり、Foursquareの認可画面が表示されます。

認可ボタンをクリックすると、先程のVisualforceページに戻り、今回はアクセストークンが取得できていることがわかります。

![fsat.jpg](https://qiita-image-store.s3.amazonaws.com/0/6495/c5ead190-e3c4-8bb8-8476-cf6c254f5c7e.jpeg)

# まとめ

以上で、Force.com の中から簡単に外部APIのOAuthアクセストークンが取得できました。あとはApexであれVisualforce内のJavaScriptであれ、HTTPリクエストのAuthorizationヘッダにBearerとして取得したアクセストークンを指定してやればオッケーです。JavaScriptからアクセスする場合でAPIがCORSに非対応である場合などは[AJAX Proxy](https://developer.salesforce.com/page/Ajax_Proxy)を使うのがよいでしょう（その際はリモートアクセスの設定を忘れないように）。

今回はFoursqureで試しましたが、もちろん他のOAuth2対応のプロバイダも利用可能です。とりあえずGithubとInstagramは試しました。GoogleはOpenID Connectにも対応してますが、もちろんOAuthだけの利用もOKです。

なおscopeの指定については、認証プロバイダの項目の中に「デフォルトの範囲(Default Scopes)」という項目がありますので、こちらに指定することが可能です。コンシューマの秘密に並んで謎訳なのはもう慣れましたね。