モバイル SDK を利用して 3Dセキュアを導入する

ここでは、モバイル SDK を利用してトークン作成時に 3Dセキュアを導入する方法について説明します。
3Dセキュアの概要については、下記ドキュメントをご覧ください。

リダイレクト URL を設定する(各 SDK 共通)

まずはじめに、管理画面 > API設定 > 3Dセキュア からリダイレクト URL を設定します。

モバイル SDK では、カード会社が提供する 3Dセキュア認証画面を表示するためにブラウザアプリを利用します。 認証を実施した後、モバイルアプリで再度処理を継続するためにリダイレクト URL とその識別子を登録します(ここで設定した URL と識別子は実装に利用します)。

URL スキームは HTTPS 以外にカスタム URL スキームを利用できます。 HTTPS スキームの URL の場合、iOS では Universal Link、Android では App Links の設定を行ってください。

3Dセキュア開始方法

各 SDK でカードフォーム開始時にオプションを指定することで、トークン作成時に 3Dセキュアを開始できます。

また、管理画面 > API設定 > 3Dセキュア よりトークン 3Dセキュアの実施モードを指定することで、パラメーターを指定することなく全てのトークン作成に 3Dセキュアを必須にすることが可能です。

管理画面でトークン 3Dセキュアを実施するモードが有効になっている場合、たとえ SDK でカードフォーム開始時に 3Dセキュアを実施しないオプションを指定しても、3Dセキュアは実施されます。

管理画面でのモード SDK でのオプション( useThreeDSecure トークン作成時の3Dセキュア
有効 true 実施
有効 false 実施
無効 true 実施
無効 false 実施されない

ここから先の設定方法は、各 SDK によって異なります。利用する SDK に合わせて設定を追加してください。

payjp-iosの場合 

XcodeでURLスキームを設定する

管理画面で追加したリダイレクト URL の設定に合わせて、アプリにも URL スキームの設定をします。

参考: Defining a Custom URL Scheme for Your App | Apple Developer Documentation

Xcode を開き、プロジェクト設定でアプリのターゲットを選択し Info タブに切り替えます。 URL Types という項目の + ボタンからスキーム設定を追加し、管理画面で登録したリダイレクト URL のスキームを設定します。

たとえば、リダイレクト URL が jp.pay.example://tds/finish の場合、以下のように jp.pay.example を設定します。

リダイレクトURLを登録する

管理画面で指定したリダイレクト URL と識別子を登録します。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {

    PAYJPSDK.publicKey = YourPayjpPublicKey
    PAYJPSDK.locale = Locale.current
    PAYJPSDK.threeDSecureURLConfiguration =
        ThreeDSecureURLConfiguration(redirectURL: URL(string: "jp.pay.example://tds/finish")!,
                                     redirectURLKey: "mobileapp")

    return true
}

カスタム URL スキームによってアプリが起動された際、 ThreeDSecureProcessHandlercompleteThreeDSecureProcess(url:) を呼び出すことで、認証フローを完了します。

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    return ThreeDSecureProcessHandler.shared.completeThreeDSecureProcess(url: url)
}

カード所有者を 3Dセキュアに誘導する

カードフォーム画面を利用している場合

CardFormViewController.createCardFormViewController() を利用してカードフォーム画面を呼び出している場合は、SDK が自動的にハンドリングするため、カードフォーム開始時に 3Dセキュアの実施を指定するのみです。

let cardFormViewController = CardFormViewController.createCardFormViewController(
    delegate: self, 
    useThreeDSecure: true
)

それ以外の場合

3Dセキュアの認証を実施するには、 createToken の引数 useThreeDSecuretrue を指定します。

createToken によって取得した TokenToken.card.threeDSecureStatus.unverified の場合、3Dセキュアの認証を開始してください。

まず、 ThreeDSecureProcessHandler.startThreeDSecureProcess(viewController:delegate:token:) の第3引数に取得した Token を渡します。

これにより、SDK はブラウザを開きカード所有者を認証画面へと誘導します。認証が完了、失敗、またはキャンセルによって終了するまで、SDK によるトークン作成処理は中断状態となります。

self.cardFormView.createToken(useThreeDSecure: true) { [weak self] result in
    guard let self = self else { return }
    switch result {
    case .success(let token):
        if tdsStatus = token.card.threeDSecureStatus, status == .unverified {
            ThreeDSecureProcessHandler.shared.startThreeDSecureProcess(viewController: self,
                                                                       delegate: self,
                                                                       token: token)
        } else {
            // 取得したトークンを扱う
            self.onSuccess(token)
        }
    case .failure(let error):
            // エラー処理
        }
    }
}

認証が終了し、リダイレクト URL によって ThreeDSecureProcessHandler.completeThreeDSecureProcess(url:) が呼び出されることで、SDK は認証フローの終了を検知します。 ThreeDSecureProcessHandlerDelegate をアプリの ViewController に適合し、 threeDSecureProcessHandlerDidFinish(_:status:) で受け取る ThreeDSecureProcessStatus に応じてトークン作成処理を完了させてください。

public func threeDSecureProcessHandlerDidFinish(_ handler: ThreeDSecureProcessHandler,
                                                status: ThreeDSecureProcessStatus) {
    switch status {
    case .completed:
        // 3DSの処理を完了する
        completeTokenTds()
    case .canceled:
        // UI更新など
    default:
        break
    }
}

ThreeDSecureProcessStatus.completed の場合、先に取得した Token を利用して認証済みの Token を取得できます。 APIClient.finishTokenThreeDSecure(tokenId:completion:) を利用して再取得を行ってください。

let completion: (Result<Token, APIError>) -> Void = { [weak self] result in
    guard let self = self else { return }
    switch result {
    case .success(let token):
        self.onSuccess(token)
    case .failure(let error):
        self.onFailure(error)
    }
}
if let token = self.pendingToken {
    APIClient.shared.finishTokenThreeDSecure(tokenId: token.identifer, completion: completion)
}

以上でトークン作成時に 3Dセキュアを要求する iOS の実装は完了です。

payjp-androidの場合

リダイレクトURLを登録する

管理画面で指定したリダイレクト URL と識別子を登録します。

Payjp.init(PayjpConfiguration.Builder(YOUR_PUBLIC_KEY)
    .setThreeDSecureRedirectName("mobileapp") // URLではなく識別子を登録します
    .build())

AndroidManifest.xmlにIntentFilterを追加する

アプリの AndroidManifest.xml に管理画面で指定したリダイレクト URL を追加します。アクティビティとして jp.pay.android.verifier.ui.PayjpThreeDSecureStepActivity を追加し、IntentFilter を設定します。

たとえば、リダイレクト URL が my-app://tds/complete の場合、以下のように記述します。

<activity android:name="jp.pay.android.verifier.ui.PayjpThreeDSecureStepActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="my-app" android:host="tds" android:path="complete" />
    </intent-filter>
</activity>

カード所有者を3Dセキュアに誘導する

カードフォーム画面を利用している場合

Payjp.cardForm().start() を利用してカードフォーム画面を呼び出している場合は、SDK が自動的にハンドリングするため、カードフォーム開始時に 3Dセキュアの実施を指定するのみです。

Payjp.cardForm().start(
    activity = this,
    face = PayjpCardForm.FACE_MULTI_LINE,
    extraAttributes = arrayOf(ExtraAttribute.Email()),
    useThreeDSecure = true,
)

それ以外の場合

3Dセキュアの認証を実施するには、 createToken の引数に useThreeDSecure = true を指定します。

createToken によって取得した TokenToken.card.threeDSecureStatusUNVERIFIED のとき、3Dセキュアの認証を開始してください。

まず、 Token.retrieveId() で得られる TokenId を、 Payjp.verifier().startThreeDSecureFlow(TokenId, Activity) の第1引数に渡します。

これにより、SDK はブラウザを開きカード所有者を認証画面へと誘導します。認証が完了、失敗、またはキャンセルによって終了するまで、SDK によるトークン作成処理は中断状態となります。

以下の例は PayjpCardFormFragment#createToken を利用した場合です。

cardFormFragment.createToken(useThreeDSecure = true).enqueue(object : Task.Callback<Token> {
    override fun onSuccess(data: Token) {
        if (data.card.threeDSecureStatus == ThreeDSecureStatus.UNVERIFIED) {
             Payjp.verifier()
                .startThreeDSecureFlow(data.retrieveId(), this@SampleActivity)
        } else {
            sendTokenToServer(token: data)
        }
    }

    override fun onError(throwable: Throwable) {
        updateUI(throwable)
    }
})

認証が終了すると、Payjp.verifier().startThreeDSecureFlow(TokenId, Activity) の第2引数に渡した呼び出し元の Activity(または Fragment)で onActivityResult に結果を受け取ります。

Payjp.verifier().handleThreeDSecureResult(requestCode, callback) を使って認証フローの結果を取り出し、コールバックで渡される PayjpThreeDSecureResult に応じて処理を再開してください。 PayjpThreeDSecureResult#isSuccess() が true の場合は認証フローが完了していることを表します。

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    Payjp.verifier().handleThreeDSecureResult(requestCode) { result ->
        if (result.isSuccess()) {
            this.onCompleteTds(result)
        } else {
            Toast.makeText(this, "3-D Secure canceled.", Toast.LENGTH_SHORT).show()
        }
    }
}

3Dセキュアの認証に成功した場合、Payjp.verifier().completeTokenThreeDSecure(result) で認証済みの Token を取得します。

if (!result.isSuccess()) {
  return
}
Payjp.token().completeTokenThreeDSecure(result)
    .enqueue(object : Task.Callback<Token> {
        override fun onSuccess(data: Token) {
            Log.i("PAY.JP", "token => $data")
        }
        override fun onError(throwable: Throwable) {
            Log.e("PAY.JP", "failure getting token", throwable)
        }
    })

以上でトークン作成時に 3Dセキュアを要求する Android の実装は完了です。

payjp-react-native-pluginの場合

カードフォーム画面を利用する方法以外はサポートしていません。

各プラットフォームごとにリダイレクトの設定をする

iOS では、payjp-ios同様、XcodeでURLスキームを設定します。 Android では、payjp-android同様、AndroidManifest.xmlにIntentFilterを追加します。

リダイレクトURLを登録する

管理画面で設定したリダイレクト URL と識別子を登録します。 PayjpCore#init の引数となるオブジェクトに threeDSecureRedirect というキーで下記のように URL と識別子を指定してください。

PayjpCore.init({
    publicKey: YOUR_PUBLIC_KEY,
    threeDSecureRedirect: {
        url: "jp.pay.example://tds/finish",
        key: "mobileapp",
    },
});

カードフォーム開始時に 3Dセキュアの実施を指定する

PayjpCardForm.startCardForm() の引数となる CardFormOption オブジェクトに useThreeDSecure というキーで true を指定してください。

PayjpCardForm.startCardForm({
    useThreeDSecure: true
});

payjp-flutter-pluginの場合

カードフォーム画面を利用する方法以外はサポートしていません。

各プラットフォームごとにリダイレクトの設定をする

iOS では、payjp-ios同様、XcodeでURLスキームを設定します。 Android では、payjp-android同様、AndroidManifest.xmlにIntentFilterを追加します。

リダイレクトURLを登録する

管理画面で設定したリダイレクト URL と識別子を登録します。 Payjp#init の引数となるオブジェクトに threeDSecureRedirect というキーで下記のように URL と識別子を指定してください。

Future<void> _initPayjp() async {
  await Payjp.init(
    publicKey: YOUR_PUBLIC_KEY,
    threeDSecureRedirect: PayjpThreeDSecureRedirect(
      url: 'jp.pay.example://tds/finish', key: 'mobileapp'));
}

カードフォーム開始時に 3Dセキュアの実施を指定する

Payjp#startCardForm の引数 useThreeDSecuretrue を指定してください。

await Payjp.startCardForm(
        onCardFormCanceledCallback: _onCardFormCanceled,
        onCardFormCompletedCallback: _onCardFormCompleted,
        onCardFormProducedTokenCallback: _onCardFormProducedToken,
        useThreeDSecure: true);

まとめ

モバイル SDK を利用して 3Dセキュアを導入する手順は以下のとおりです。

  1. 管理画面でリダイレクト URL と識別子を設定する
  2. 各 SDK ごとに必要な設定を行う
    • iOS の場合は Xcode で URL スキームを設定
    • Android の場合は AndroidManifest.xml に IntentFilter を追加
  3. SDK の初期化時にリダイレクト URL と識別子を登録する
  4. カードフォーム画面開始時(またはトークン作成時)に、3Dセキュアの実施を指定する(管理画面の設定によっては不要)
  5. トークン作成後、3Dセキュアが必要な場合は SDK の機能を使ってカード所有者を認証フローに誘導する
  6. 認証後のリダイレクトを受け取り、SDK の機能で認証済みのトークンを取得する

これらの手順に沿って実装を行うことで、モバイルアプリでも安全なクレジットカード決済を提供できます。 セキュリティ強化のため、ぜひ 3Dセキュアの導入をご検討ください。

リファレンス