弊社のアプリケーションではモバイルアプリの認証にAuth0を利用しています。 そして、Auth0からユーザーに利用可能な認証方式の1つとしてSign in with Appleを採用しています。
Sign in with appleを認証で利用していると、さらに追加でユーザーに氏名の入力を求めているとストアの審査ガイドラインで落されてしまいます。 そこで、Auth0側から情報をとりだすようにして入力はスキップさせる必要があります。
本来、Sign in With Appleで認証したユーザーの情報はAuth0に保管されるので、 Auth0のAPIを叩く事でAppleから取得できていたユーザーの氏名等を本来取得できるはずなのですが、現在(日本時間 2021/02/20 2:00)の時点では 氏名の情報を返すパラメータ名がAuth0とAppleの間で同期できておらず、正常に取得ができなくなってしまっておりましたので、調査して暫定の対応をしました。
発生していた事象
Auth0からfamily_name, given_nameがかえってこない
Sign in with AppleでAuth0で認証したユーザーの
family_name
および given_name
をフィールドをサーバーサイドから取得しようとしたのですが、値が返ってこず取得できなくなっていました。
first_name, last_nameというフィールドにははいっているがAPIからは取得できない
Auth0のユーザー一覧を確認しにいってみると, first_name
, last_name
というフィールドにどうも氏名の情報がはいっているようです。
ではこの値を取得できないのかとしたかったのですが、このフィールドを取得しようとRubyのSDKから叩くとBad Request Errorが発生します
Auth0::BadRequest ({"statusCode":400,"error":"Bad Request","message":"Query validation error: 'String 'first_name,last_name' does not match pattern. Must be a comma separated list of the following values: phone_number,email,email_verified,picture,username,user_id,name,nickname,created_at,identities,app_metadata,user_metadata,last_ip,last_login,logins_count,updated_at,blocked,family_name,given_name' on property fields (Comma-separated list of fields to include or exclude (based on value provided for include_fields) in the result. Leave empty to retrieve all fields).","errorCode":"invalid_query_string"})
たしかに、Auth0のAPIドキュメントを見てもUserのフィールド名としてはfamily_nameやlast_nameというのは存在しません
ではなぜ、Auth0はfamily_name, given_nameという名称に限定しているのだろうという事を調査してみると、 このAuth0のフォーラムでも推測されていたのですが
どうも、OIDC標準では氏名のフィールド名はfamily_name
given_name
とする事となっており、
first_name
last_name
というのはAppleの独自の仕様のようです
おそらくですが、ここの同期というかマッピングがAuth0側でまだ対応されておらず、Auth0には保存されているが読みだす事はできないという状態になってしまっているようです。
暫定対応方法
フォーラムの方法は残念ながらそのままでは動かなかった
上記のフォーラムでは、Ruleの中でAppleから情報を取得した時は、family_name
, given_name
の値をupdateするという方法はどう? という方法が推奨されています。
しかし、現時点で実際にそのRuleを設定してみると、以下のエラーが発生しました。
{"statusCode":400,"error":"Bad Request","message":"The following user attributes cannot be updated: family_name, given_name. The connection (apple) must either be a database connection (using the Auth0 store), a passwordless connection (email or sms) or has disabled 'Sync user profile attributes at each login'. For more information, see https://auth0.com/docs/dashboard/guides/connections/configure-connection-sync"
エラーを読むかぎりでは、appleからの情報取得で発行されたユーザーの family_name
given_name
という
フィールドの更新はログイン時のプロフィールの自動同期をオフにしない限りは利用できないようです、
名前にかぎらず他のプロフィールの同期の事も考えるとこのためだけに同期を切るというのもいただけないので、他の対応を考える事としました。
user_metadataに保管する
そこで、暫定対応としてですが user_metadata
というなんでも保管しておけるattributeに目をつけました。
family_name, given_nameを直接更新するのではなく、そちらのメタデータにほうりこんでしまうのです
function (user, context, callback) { // you might want to add a check to only run this // if `user.family_name` and `user.given_name` is actually missing if (context.connectionStrategy === "apple") { var ManagementClient = require('auth0@2.32.0').ManagementClient; var management = new ManagementClient({ token: auth0.accessToken, domain: auth0.domain }); // persist in user store management.updateUser({id: user.user_id}, {user_metadata: { apple_family_name: user.last_name, apple_given_name: user.first_name }}) .then(function(u){ callback(null, u, context); }) .catch(function(err){ callback(err); }); } else { // if not apple callback(null, user, context); } }
このようにするとエラーが発生する事なく
"user_metadata": { "apple_family_name": "Tesuto", "apple_given_name": "Taro" },
とAuth0上に情報が保存される事が確認できました。
サーバーからはフォールバックしながら読みだす
user_metadataフィールドはAPIから読み出す事ができるので、サーバー上で他の認証方式では 正常にとれているはずのfamily_name、given_nameを優先しながら、次善の策としてこのメタデータにフォールバックする形式に変更しました。
user_profile = auth0_client.user( auth0_subject, fields: "family_name,given_name,user_metadata" ) family_name = user_profile["family_name"] || user_profile.dig("user_metadata", "apple_family_name") given_name = user_profile["given_name"] || user_profile.dig("user_metadata", "apple_given_name")
これで、無事にサーバーからApple以外の認証方式とも両立させながら無事情報取得が可能になりました..早めに公式で解決すると良いな...