Web版「Sign In with Apple」を実装する

  • このエントリーをはてなブックマークに追加
  • LINEで送る

今年のWWDCで発表された「Sign In with Apple」のWeb版(JavaScript版)を実装してみたいと思います。

今回、裏側はFirebaseを利用していますが、Authenticationは使っていませんので、一般的な環境でも参考になると思います。(執筆時点でまだFirebaseが未対応なので使いたくても使えないわけですがw)

- Sponsored Link -

AppleIDでログイン

サンプル

以下のページで実際の動作を確認できます。

  • PC、スマホ(iOS,Android)ともに動作します。
  • 2段階認証(多要素認証)を設定している場合はID/PWでログイン後に聞かれることになります。
  • このサンプルではログイン情報の記録はしていません。

ソースコード

index.html

最初のページです。ログイン用のボタンが表示されます。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Test for 「Sign In with Apple」</title>
</head>
<body>

<!-- ボタン -->
<div id="appleid-signin"
  data-color="white"
  data-border="true"
  data-type="sign in">
</div>

<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
<script type="text/javascript">
  // 本来はCSRF対策用の文字列を準備してください
  const rand = 'ST' + Math.ceil( Math.random() * 100000 );

  // ログイン処理
  AppleID.auth.init({
        clientId : "net.miku3.id.apple.service",
           scope : "email",
      redirectURI: "https://miku3.net/appleid/callback",
           state : rand
  });
</script>
</body>
</html>

AppleID.auth.init()に渡す引数はそれぞれ以下の通り。

項目説明
clientIdAppleのDeveloperサイトでIdentifier作成時に設定した値をそのまま書きます(後述)
scope取得したいユーザー情報を記述します。ユーザー名とメールアドレスの指定が可能ですがどちらもWebからだと現状取得できません。
redirectURIログイン後に戻ってくるURIを記述します。Developerサイトへ事前に登録しておく必要があります(後述)
stateCSRF対策用の文字列を指定します(後述)

またボタンの表示で利用する属性の内容は以下の通り。

属性説明
data-colorボタンの背景色を指定。blackまたは white
data-border枠線を表示するかをBooleanで指定。
data-typeボタンの種類を指定。sign in, sign up, continue, appleの中から選択

ボタンの大きさはCSSで変更可能です。

.signin-button {
  width: 210px;
  height: 40px;
}

デザイン周りの詳細はAppleのガイドラインを参照してください。

callback

無事にログインした後に表示されるページです。
ログイン時にredirectURIで指定したURLに、POSTメソッドで戻ってきます。今回はFirebaseのCloudFunctions(Node.js)を利用していますが、Appleから送られてくるクエリーの値をJSON風に表示しているだけです。

実際に利用する場合はログイン時に渡したstateの値がreq.body.stateにそのまま入っていますので必ずチェックを行ってください。

const functions = require("firebase-functions");

exports.appleidCallBack = functions.https.onRequest( (req, res) => {
  const buff = ( req.method === "POST" )? req.body:req.query;

  // このあたりでCSRF対策用の文字列(req.body.state)のチェック

  res.send(
      "<h1>Wellcome Back</h1>"
    + "<pre style=\"border:1px solid gray;\">"
    + JSON.stringify(buff, null, 4)
    + "</pre>"
  );
});

Firebase.jsonでrewritesの部分を以下のように書き足しています。これで/appleid/callbackへリクエストが来ると、上記のCloudFunctionsが実行されるようになります。

{
  "hosting": {
    "public": "public",
    "rewrites": [ {
        "source": "/appleid/callback", "function": "appleidCallBack"
      }],
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  }
}

CloudFunctionsを独自ドメインで利用する方法については以下の記事を参照ください。

CSRF対策

stateで指定する値は、このページを識別するためのコードと、セッションIDなどを組み合わせた物にしておけば良いと思います。

PHPで書くなら以下のような感じ。唐突なPHPw!

// このページのCDを定義
define('PAGE_CD', 'AUTH-APPLE');

// セッション開始
session_start();

/**
 * Stateの値を生成
 */ 
function getState(){
  $page_cd = PAGE_CD;       // ページを識別するためのCD
  $sess_id = session_id();  // 本人を識別するためのID

  return(sha1($page_cd . $sess_id));
}

/**
 * Stateの値をチェック
 */
function checkState(){
  $page_cd = PAGE_CD;;        // ページを識別するためのCD
  $sess_id = session_id();    // 本人を識別するためのID
  $state   = $_POST['state']; // Appleから渡されたstate

  return(
    sha1($page_cd . $sess_id) === $state
  );
}

index.htmlgetState()で生成した値を渡し、redirectURIで指定したURIのページに戻ってきた際にcheckState()でチェックするイメージです。

Appleから渡される値

redirectURIで指定したURIにPOSTメソッド戻ってくるわけですが、このときに以下のような値が渡されます。

クエリー名説明
stateAppleID.auth.init()で渡したstateの値がそのまま入っています
code5分間有効なシングルサインオン用の値
id_tokenユーザーを識別するためのID

scopeemailを指定しましたがガン無視されますw 現状だとWeb版はメールアドレスはおろかユーザー名さえも取得できないみたいですね。NDKだとこのあたりうまく行くようなので、どうしてもこれらの情報がほしい場合はiOS用のネイティブアプリを利用することになりそうです。

Appleサイトでの準備

デベロッパー登録

詳細は割愛しますがAppleへデベロッパー登録を行う必要があります。クレジットカードが必要で毎年11,800円かかります(執筆時点)。ついでにiOSやmacOS用アプリの開発や配信も行えますので、興味があればどうぞw

昔は1万円未満だったんですけど、徐々に高くなってますね…。個人だと微妙にウッとなるお値段ですw

App IDの作成

最初にこれから「アプリ」を作るぞ!とAppleに意思表示をする必要があります。今回はWebサイトでログインさせるだけですので、ここでいう「アプリ」は概念的な物だと思ってください。

まずはDeveloperサイトへログインします。

ログイン後に左メニューの「Certificates, Identifiers & Profiles」をクリック。

どんなアプリを作るか入力します。

  • Platformは「iOS
  • Descriptionは説明文になりますので自分が後から見てわかる文字列であれば何でも良いです。
  • BundleIDはこのアプリを識別するためのユニークなIDです。URLのドメインを反対にしたような文字列を記述します。URLではありませんので存在しないURLのような文字列で構いません。なお世界中の全アプリからユニークである必要があるので通常は自分が所有しているドメイン名を利用します。

まだ次のページに進んではなりません。
ページ下部にある以下の「Sign In with Apple」にチェックをした後に、ページ上部にある青い「Continue」ボタンをクリックします。横にある「Edit」ボタンはクリックしなくてOKです。

確認画面を挟んで最終的に以下のように一覧に表示されていれば成功です。

Identifierの作成

次に「アプリ」で利用する機能の詳細な設定を行います。
先ほどの画面で「Identifiers」の横にある「+」ボタンをクリックします。

「Services IDs」にチェックし「Continue」ボタンをクリック。

ここから具体的な設定項目に入ります。

  • Descriptionは説明文になりますので自分が後から見てわかる文字列であれば何でも良いです。
  • Identireはこの設定を識別するためのユニークなIDです。BundleIDと同様にドメインを反対から書いたような書式になりますが、BundleIDとの重複は許されません。index.htmlのclientIdにはこの文字列を指定します。
  • Sign In with Apple」の横にあるEnableのチェックボックスにチェック

お次は横にある「Edit」ボタンをクリック、以下のような設定画面が開きます。

  • Primary App IDは先ほど作成した「アプリ」を選択します。一つしか無い場合は最初から選ばれています。
  • DomainsにはログインページとredirectURIで指定するページが存在するドメインを入力します。これは複数入力できない点に注意が必要です。
  • ReturnURLsにはredirectURIで指定するURLを指定します。ここに登録していないURLをredirectURIで指定するとエラーとなります。

登録が終わったら「Download」ボタンを押して、指定したドメインの所有者であることを証明するために必要なファイル「apple-developer-domain-association.txt」をダウンロードします。これは後ほど利用します。

あとは画面の指示に従い、最終的に一覧画面に登録したIdentifierが登場すれば成功です。

ドメイン認証

最後にIdentifierの設定で登録したドメインが自分の物であることを証明するために、先ほどダウンロードした「apple-developer-domain-association.txt」を所定の場所にアップロードします。

アップする場所はIdentifierの設定画面で表示されている以下。

ドキュメントルートに.well-knownというディレクトリを作成し、その中にダウンロードしてきた「apple-developer-domain-association.txt」を放り込みます。ディレクトリ名の頭に「.」を付けることをお忘れなく。

以上で登録作業は完了です。

雑感

ログインさせるだけであれば非常に簡単ですね。ただメールアドレスなどの情報が取れないのは正式版では解決するのかな…。あとWeb上でサンプルをあまり見かけないのはAppleへのみかじめ料のせいですかねw

恐らく秋ごろには正式に始まると思いますので、そのあたりになったら実際のサービスへ組み込んでみたいと思います。

参考ページ

Apple

その他

- Sponsored Link -

ご質問やリクエストなどお気軽に。メールアドレスの入力は任意です。書き込みが反映されるまで時間がかかります。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください