Help us understand the problem. What is going on with this article?

Sign In with Apple をサーバーサイドで実装するときのポイント

iOS 13でリリースされた「Sign In with Apple」。iOSやmacOSなどの場合はAuthenticationServices Frameworkを使うことで実装できますが、きちんと対応するにはWebからもログインできるようにする必要があるサービスも多いと思います。

Webで Sign In with Apple を実現するための手段として「Sign In with Apple JS」という JavaScript SDK が Apple から提供されていますが、既存のサードパーティーログインと合わせてサーバーサイドで実装が必要なケースもあると思います。独自で実装する場合に参照するべきリソースがわかりづらかったので、ポイントと一緒にまとめます。

(2020/3/7 追記) Apple より、2020/4/30 までに、サードパーティーログインを使っているアプリについては、 Sign In with Apple に対応しなければいけないという発表がありました。2020年5月以降、対応していないアプリは審査に通らなくなります。

Apple Developers で行う事前準備

実装をする前に、Apple Developers (Certificates, Identifiers & Profiles) でいくつか設定が必要になるためご紹介します。

Register Domains and Emails for communication

「メールアドレスを隠す」設定でサインインしたユーザーに対して、メールを送信するための設定が More メニューに隠れています。メールアドレスを隠すとabcde12345@privaterelay.appleid.com のようなメールアドレスを取得できますが、このアドレス宛にメールを送信するには、送信元のアドレスまたはドメインがこのメニューで登録されている必要があります。

ドメイン認証の場合はそのドメイン直下に /.well-known/apple-developer-domain-association.txt を置くことで、メールアドレスの場合は認証メールを使って登録を行います。

なお、この項目はアプリとWebで共通のため、すでにアプリ実装時に設定している場合は再設定の必要はありません。

Service IDs

WebサイトでSign In with Appleを実装するには、Service IDを作成する必要があります。 Identifiers メニューから作成することが可能ですが、Sign In with Appleの設定をする際に、対応するApp IDが必要となります。

ここで設定するApp IDはリリースされていなくてもかまいませんが、サインイン時に表示されるサービスのアイコンはこのApp IDに紐付いたリリース済みアプリのアイコンが使われるようなので注意が必要です(リリースされていない場合はブランクのアイコンが表示されます)。

そのほか、Service IDsのSign In with Apple設定では、設置するサイトのドメイン認証と、コールバックURLの登録を行います。HTTPのlocalhostは指定できなかったので、ローカル環境でテストを行う場合はngrokなどを使うと良さそうです。

Keys

Service IDs の登録が終わったら、Key の作成を行います。Keys メニューから、
Sign In with Appleのキーを作成します。ここでもApp IDの選択が必要です。

Key の登録が完了すると、 .p8 形式の暗号鍵ファイルをダウンロードすることができます。この鍵を後ほど使用するため、必ずダウンロードしておいてください。

サーバーサイドで実装する際のポイント

Authorize

Authorize エンドポイントに関する情報は Incorporating Sign in with Apple into Other Platforms に記載されています。

パラメータとして指定する内容は client_id, redirect_uri, scope など一般的な認証エンドポイントと同様でです。 client_id には、Service ID 作成時に入力した Identifier を使います。

注意すべきポイントとして、 scope に値を指定した場合(メールアドレスを取得する場合など)は response_modeform_post を指定する必要があります。この値を指定すると redirect_uri へのコールバックが POST形式 となりますので注意が必要です。なお、このレスポンスに scope で指定した内容が初回の認証に限り含まれていますが、Apple におけるユーザーごとに一意の値 (sub) の値を取得する場合は、後段の Token エンドポイントを叩く必要があります。

Token

Token エンドポイントに関する情報は Generate and validate tokens に記載されています。

ここで初めて client_secret というパラメータが登場しますが、このパラメータはドキュメント後半にも記載されている通り、JWTを指定します。つまり、Appleが発行するJWT(IdToken)を取得するために、自分がApple向けのJWTを発行する必要があるのです。

JWTの各項目に指定する内容は以下の通りです(現時点でドキュメントに記載の内容を転載します)。

キー
header alg ES256
kid Apple Developer で発行したキーの Key ID (10桁)
payload iss Apple Developer で確認できる自分の Team ID (10桁)
aud https://appleid.apple.com
iat 現在時刻 (エポック秒)
exp 現在時刻から6ヶ月以内の任意の時刻 (エポック秒)
sub Service ID 作成時に入力した Identifier

これらの値を使ってJWTを作成しますが、このとき発行しておいた暗号鍵を使って署名します。アルゴリズムが ES256 と指定されていますので、ECDSA形式に対応したライブラリを使ってJWTを作成しましょう。作成したJWTを client_secret として使用します。

なお、 refresh_token を使ってトークンを再取得する際もこのエンドポイントを使用します。

(2020/3/7 追記) ここで発行した JWT は、 exp で指定した有効期間内であれば使い回すことが可能なため、ユーザーのログインリクエストごとに毎回発行し直す必要はありません。事前に発行したものを環境変数などに入れておくなどすることで、 JWT の発行機能をアプリケーションに組み込むことなく実装することができます。ただし、 exp に設定できる期間は最長で6ヶ月のため、有効期限が切れる前に確実に JWT を発行し直す、または定期的に発行し直す仕組みを整えるなどする必要があります。

Token エンドポイントからの返却値について

Token エンドポイントからは TokenResponse というオブジェクトが返却されます。 id_token をデコードすることで sub を含むClaimを取得することが可能です。

Authorizeエンドポイントの際と同様に、 email など scope として指定した項目についてはユーザーごとの初回の認証に限り ID Token の payload として含まれています。2回目以降にユーザーがログインした場合はこれらの値が含まれていない ID Token が発行されるため、 sub などの値を用いてユーザーの突き合わせを行うようにしましょう。

JWK

ID Token の署名を確認するための公開鍵については Fetch Apple's public key for verifying token signature にエンドポイントが記載されています。

Profile

OAuth認証を提供するサービスの中には、Token エンドポイントで取得した Access Token を使ってユーザー情報を取得できる Profile エンドポイントが用意されている場合がありますが、 Sign In with Apple では現時点でそのようなエンドポイントは用意されていません(そもそもアクセストークンが払い出されません)。

ID Token 以上の情報を取得することはできませんので、ID Token の内容を使ってユーザー登録を完了させましょう。

そのほか

Sign In with Apple ボタン

Sign In with Apple JS を使わずに認証を実装する場合のボタン画像については、 Incorporating Sign in with Apple into Other Platforms に、パラメータを指定して画像がダウンロードできるURLが記載されています。

が、URLのパラメータをちまちまいじって画像を取得するとかやってられないので、生成用ツールを作りました。パラメータを入力してCreateボタンを押すとボタンが生成できますので、必要に応じてご利用ください。(なぜか border パラメータが反映されないのですが、どなたか原因ご存知の方いらっしゃいますか……?)

Sign In with Apple に関する Human Interface Guideline には、ここで生成したボタンの利用に関するルールが記載されています。ちなみに、ここを読んだ限りでは「公式のボタンを必ず使わなければいけない」とは記載されていない(推奨されているだけ)みたいです。いずれにしても、ユーザーがひと目で理解できるボタンを使用しましょう。

Sign In with Apple の管理

これまでどのサービスに対して Apple ID でのサインインを行ったかについては、Apple ID の管理画面で確認することが可能です。ここからIDの利用を解除することもできますので、初回ログインの動作を繰り返し確認したい場合などはこちらを使いましょう。

さいごに

REST API のドキュメントの Endpoint に Authorize エンドポイントに関する情報がない、client_secret としてJWTを生成する必要があるなど、ドキュメントや実装に若干クセのあるAPIですが、2020年3月末までに(サードパーティー製ログインを実装している場合は)既存アプリも対応が必須になっていますので、ぜひ早めに手を付けて対応しておきましょう。このページがその一助となれば幸いです。

(2020/3/7 追記) 本ページの内容をもとに、 PHPerKaigi 2020 懇親会にて飛び入りLTさせていただきました(「Sign In with Apple のつらみ」)。

kiwi26
東京でスマートフォンアプリとか作ってます
nifty
インターネット接続やブログといったインターネット関連サービスを開発・提供している企業です。
http://www.nifty.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした