株式会社スマレジの開発部でスマレジのサーバサイドを作っています

スマレジプラットフォームAPIで、購入者情報を認証する

こんにちは!株式会社スマレジ、開発部のmasaです!

4連休はエンジョイされてますか?masaは大学の友人と久しぶりにzoomで喋ってたりと、相変わらずインドアに過ごしています。

普段なら、ゆとりがあれば学祭に顔を出したりするんですが、コロナのせいで中止になったりで、今年はリモート参加になりました。

さて、今回は、アプリを購入してくれたスマレジユーザを認証する方法を見ていきます。

購入者の認証方法

今回お話しする内容は、主にディベロッパーズサイトのスマレジ・プラットフォームAPI 共通仕様書の利用者通知とログイン(β)に関連した内容になります。

developers.smaregi.dev

ログイン機能についてはβの記載があるように、この仕様は変更されることがあります。この記事記載時点(2020-09-20)での内容であることをご承知おきください。

購入通知のWebhookから購入者情報を取得する

前回のブログでも、チラッと触れましたが、上記リンクの「利用者通知」の項目に、「アプリを購入/削除したタイミングで、購入者の情報に関するWebhookが飛ぶ」旨の記載があります。

このWebhookには、スマレジの契約IDがヘッダ・ボディの両方に含まれており、これでその契約IDを持つユーザが自分のアプリを「購入・削除」したことがわかります。

Webhookの送信先設定については、前回のブログを参照してください。

masa2019.hatenablog.com

通知受信用のエンドポイントで、ユーザ情報をうち、契約IDを登録しておくことになります。

アプリ認証を実施する

スマレジでは、アプリを購入したユーザのデータをAPIで取得するには、下記のようなページで購入者に認証をさせる必要があります。

f:id:masa2019:20200920235335p:plain
認証画面の例

このページにアクセスは、

http://id.smaregi.dev/authorize?response_type=code&client_id={クライアントID}&scope=openid&state={任意の文字列}&redirect_uri={アプリの設定で登録したリダイレクトURL}

このような形式のURLになります。

こちらで認証が成功すると、「認証コード」が発行されます。

認証コードベースで、契約IDを取得する。

こちらは実装例がありますので、こちらを参考にしてみてください。(GASです)

/**
 * 認証コードから契約IDを取得する
 * @param {string} code 認証コード
 * @return {string} 契約ID
 * @throws {Error} 受診失敗した時
 */
function authorize(code) {
    const clientId = PropertiesService.getScriptProperties().getProperty("SMAREGI_APP_CLIENT_ID");
    const secret = PropertiesService.getScriptProperties().getProperty("SMAREGI_APP_SECRET");

    const grantType = "authorization_code";
    const redirectUri = PropertiesService.getScriptProperties().getProperty("REDIRECT_URI");
    const url = 'https://id.smaregi.dev/authorize/token';
    const headers = {
        'Authorization': 'Basic ' + Utilities.base64Encode(clientId + ":" + secret, Utilities.Charset.UTF_8),
        'Content-Type': 'application/x-www-form-urlencoded'
    };

    const payload = {
        'grant_type': grantType,
        'code': code,
        'redirect_uri': redirectUri
    };

    Logger.log(payload);
    // urlfetchappのオプション情報
    const options = {
        'method': 'post',
        'headers': headers,     // header情報を追加
        'payload': payload,      // トークンを設定
        'muteHttpExceptions': true
    };

    try {
        //外部へアクセスさせる
        let resStr = UrlFetchApp.fetch(url, options).getContentText();
        if (resStr.length === 0) {
            throw new Error("受信データがありませんでした。");
        }
        let resJson = JSON.parse(resStr);
        Logger.log(resStr);
        const accessToken = resJson.access_token;
        const tokenType = resJson.token_type;
        const getContractHeader = {
            'Authorization': tokenType + ' ' + accessToken
        };

        const getContractOptions = {
            'method': 'post',
            'headers': getContractHeader     // header情報を追加
        };

        const getContractUrl = 'https://id.smaregi.dev/userinfo';

        resStr = UrlFetchApp.fetch(getContractUrl, getContractOptions).getContentText();
        Logger.log(resStr);
        resJson = JSON.parse(resStr);
        return resJson.contract.id;

    } catch (e) {
        Logger.log("エラー:" + e);
        throw new Error(e);
    }
}