PAY.JPにおける3D セキュア

3D セキュアの基本的な説明については、こちらのガイドをご覧ください。

PAY.JPにおける3Dセキュアの種類

PAY.JP では、下記の三種類の 3Dセキュア実施方法があります。

3Dセキュア義務化要件を満たすためには、下記のどちらかを実施する必要があります。

  • すべての支払い作成前に、使われるカードに対してのトークン作成時の3Dセキュアを行う
  • すべての支払い作成時に3Dセキュアを行う

上記を併用することも可能ですが、基本的に全件に対して3Dセキュアを実施することが求められます。
また、それ以外のタイミングにおいても不正が疑われる場合や定期課金を行なっている場合などにはカードに対する3Dセキュアの実施が求められる場合があります。

どの方法を使うかの検討には3Dセキュアの各組み込み方法ごとの導入指針をご覧ください。

個人情報の取得について

3D セキュアでは、取引の安全性を確認する目的で、エンドユーザーの一部個人情報を取得します。 ご利用にあたっては、加盟店様のページ上で個人情報の取り扱いについて同意を得ていただく必要があります。 詳しくは下記資料の「顧客からの同意取得について」をご確認ください。

PAY.JP 3Dセキュア ご紹介資料

3Dセキュア実装手順

PAY.JPにおける3Dセキュアのどれを使うかを加盟店様にて選択していただく必要がございます。
この時、導入指針を参考に義務化要件を満たすようにご検討ください。

基本的な3Dセキュアの流れとしては下記となります。

  1. 3Dセキュア処理待ち状態のリソースを作成
  2. 3Dセキュア開始エンドポイントへエンドユーザーを誘導
  3. カード発行会社認証画面にて認証を行う
  4. エンドユーザーが認証を終えたことを検知
  5. 認証結果のハンドリング(成功なら3Dセキュア完了エンドポイントへリクエスト等)

具体的な実装方法は3Dセキュアの種類によりますため、個別のページを参照してください。

3Dセキュアワークフロー

3Dセキュアを組み込む際、ブラウザで認証させる場合は下記のワークフローでの組み込みが可能です。
どのワークフローを選んでも認証の成功・失敗には影響しませんが、実装までの流れが大きく変わります。
またユーザーからの画面の見え方にも影響の出るものですので、御社サービスでの実装方針に合わせて最適なものをお選びください。

基本的には、サブウィンドウ型であった場合ライブラリにより実装が簡便化できますが、多くの環境で動作させたい場合はリダイレクト型をご検討ください。

モバイル SDKを使って3Dセキュアを行う場合、ワークフローはこのどちらともなりません。
詳細な実装方法はモバイル SDK を利用して 3Dセキュアを導入するをご覧ください。

●サブウィンドウ型

3Dセキュア認証画面を表示するサブウィンドウを表示し、購入者はその内部に表示されるカード発行会社の画面上でパスワード入力等を行います。
一部環境(モバイルにおけるアプリ内ブラウザなど)ではポップアップに対して警告やブロックが働くため、利用者によっては認証画面に辿りつけないこともございます。
利用状況に応じてリダイレクト型もご検討ください。

導入方法は下記のいずれかとなります。

トークン作成時の3Dセキュアの場合

クライアントライブラリが自動でカード発行会社画面上での認証および3Dセキュア完了エンドポイントへのリクエストを実施してくれます。
このやり方の場合、実装手順の全てをライブラリに任せることができます。

正常に戻ってきたトークンは支払い等に利用可能となりますが、扱いに関しては3Dセキュア認証結果のハンドリング、完了処理も参考にご利用ください。

支払い作成時の3Dセキュア、あるいはカードに対する3Dセキュアの場合

payjp.jsが提供する openThreeDSecureDialog 関数を利用できます。
openThreeDSecureDialogの使い方について詳しくはそれぞれのサブウィンドウ型実装方法についてのページをご覧ください。

このやり方の場合、実装手順の2から4をライブラリに任せることができます。
5の処理に関しては、3Dセキュア認証結果のハンドリング、完了処理を参照ください。

●リダイレクト型

サービスから PAY.JP が提供する 3D セキュア開始エンドポイントにリダイレクトさせ、認証完了後にサービスが指定するエンドポイントにリダイレクトで戻す方式です。

サブウィンドウ型に比べると実装は煩雑になりますが、一部モバイル環境ではサブウィンドウ型が適切に動作しない可能性があるため、より広い環境で動作させたい場合や、サブウィンドウのユーザー体験が望ましくない場合にはリダイレクト型をご利用ください。

PAY.JPにおける3Dセキュアの種類ごとに、3Dセキュア処理待ち状態のリソースを作成し、利用者を下記のエンドポイントにリダイレクトさせます。

https://api.pay.jp/v1/tds/:resource_id/start?publickey=....&back=...

リダイレクト時のパラメーターとして、完了後の戻り先となる URL を指定します。 このURLは、実装手順の3までが終わってから戻ってくるURLとなっており、加盟店様サーバー等で3Dセキュア完了処理を行うことになります。

戻り先 URL は、以下の 2 通りの指定ができます。

  • back
    • PAY.JP の管理画面で事前に登録した戻り先 URL を使用する場合に指定します。登録時に設定した識別子を指定してください。
  • back_url
    • 動的に戻り先 URL を指定する場合に使用します。JWS(JSON Web Signatures)形式のデータで、戻り先 URL を含めて指定します。 back_url を使用した実装はコードサンプルを参考にご実装ください。

エンドポイントとパラメーターの詳細はAPIリファレンス - 3Dセキュア開始をご覧ください。

カード会社での認証成功、あるいはエラーとなったタイミングで、利用者は指定した戻り先 URL にリダイレクトされます。 戻り先 URL では3Dセキュアの認証結果を確認し、3Dセキュア認証結果のハンドリング、完了処理を行います。

リダイレクト型3Dセキュアの実装例

支払い作成時の3Dセキュアをリダイレクト型で実施するNode.jsのサンプルコードです。

const express = require('express');
const jwt = require('jsonwebtoken');
const payjp = require('payjp');

const app = express();

const secretKey = 'sk_test_xxxxx';
const publicKey = 'pk_test_xxxxx'
const auth = Buffer.from(`${secretKey}:`).toString('base64')

function generateJwtUrl(baseUrl, params) {
  // パラメータのエンコード処理
  const encodedParams = Object.keys(params)
    .map(key => `${key}=${encodeURIComponent(params[key])}`)
    .join('&');

  // エンコード済みのクエリパラメータをURLに追加
  const encodedUrl = `${baseUrl}?${encodedParams}`;

  const payload = {
    url: encodedUrl,
  };

  // JWTを生成
  return jwt.sign(payload, secretKey, { algorithm: 'HS256' });
}

// 決済させる加盟店様側のURL
app.get('/charge', async (req, res) => {
  // 3DSのChargeを作る
  const charge = await payjp.charge.create({..., three_d_secure: true});
  const baseUrl = 'https://example.com/callback';  // 加盟店様の戻り先URL
  const queryParams = {
    param1: 'ペイ&太郎',
    param2: 'test'
  };

  // JWT付きURLを生成
  const jwtUrl = generateJwtUrl(baseUrl, queryParams);

  // 加盟店様のユーザーをリダイレクト
  const redirectUrl = `https://api.pay.jp/v1/tds/${charge.id}/start?publickey=${publicKey}&back_url=${jwtUrl}`;
  res.redirect(redirectUrl);
});

// 3Dセキュア認証を終えて戻ってきた後の処理
// 戻り先URLに指定したパスで受け付ける
app.get('/callback', async (req, res) => {
  const chargeId = req.id;
  const chargeBeforePayment = await payjp.charge.retrieve(chargeId);
  
  // chargeBeforePayment.three_d_secure_statusを見て後続処理を進めるか判断
  
  // 進める場合、完了処理
  const charge = await payjp.charge.tds_finish(chargeId)
  // chargeが作成できたら決済完了
  return res.sendStatus(200)
});

3Dセキュア認証結果のハンドリング、完了処理

実装手順の4までを終え、カード発行会社における認証の終了を検知したら3Dセキュア対象リソースを取得し状態を確認します。
リソースの three_d_secure_status を確認し、後続処理を行うかを判断します。

3Dセキュアの種類ごとの後続処理は以下の通りです。

3Dセキュアの種類 可能な後続処理 備考
トークン作成時の3Dセキュア 3Dセキュア完了エンドポイントへリクエスト 3Dセキュアなしでリソースを作成した時と同様のレスポンスが得られます。
与信枠不足などのエラーも同等に起こります。
支払い作成時の3Dセキュア 同上 同上
カードに対する3Dセキュア 加盟店様にて結果をもとにその後の処理を実施してください。 例: プラン変更時に認証を行った場合、3Dセキュアが失敗なら変更をキャンセルする

three_d_secure_statusverified または attempted であった場合、3Dセキュア認証の結果は成功とみなすことができます。
しかし例えば完全認証を行いたい場合、 three_d_secure_statusattempted の時も処理を中断することになります。

unverified のままであったり、error であったりする場合は、3D セキュアの手順中に離脱した、パラメーターに異常があった等の問題が考えられます。

3Dセキュア認証における追加項目

3Dセキュア認証 - 3Dセキュア認証の追加項目 に記載の通り、3Dセキュアを行う際にカード情報とは別に追加項目(カード名義、メールアドレスまたは電話番号)が求められるようになりました。
そのため、3Dセキュア実施までに対象カードに対して追加項目をセットする必要があります。

具体的なセット方法については、下記をご参照ください。

追加項目を送信しなかった場合

当面は追加項目のパラメーターがなかったとしても決済時にエラーにはなりません。
しかし各ブランドからは本来必須として求められている情報のため、今後厳格化しエラーとなるよう仕様変更を行う可能性がございます。
その際は別途アナウンスさせていただく予定ではありますが、加盟店様におかれましては可能な限り早めのご対応をご検討くださいますようお願いいたします。

既存カードのカード名義、メールアドレス、電話番号の更新について

過去に登録したカードに対して有効なカード名義、メールアドレスまたは電話番号が登録されていない場合、3Dセキュアを実施する前にエンドユーザーに対しデータの入力を求めるようにしてください。
収集した追加項目は顧客カード更新のAPIにてセットすることができます。

curl https://api.pay.jp/v1/customers/cus_xxxxxx/cards/car_xxxxxxxxx \
-u sk_test_c62fade9d045b54cd76d7036: \
-d name="PAY TARO" \
--data-urlencode "email=pay@example.local" \
--data-urlencode "phone=+0819001234567" \